1 solutions
-
0
难度: 蓝
算法: 强连通分量相关
说句实话,强连通分量的代码量是真多。第一次写到 100 行。
进入正题。首先跑强连通分量,缩点。对于一个强连通分量,记录这个强连通分量能否被直接购买,购买所需的最少资金,以及最小号码。
显然,所有入度为 的点都必须买,并且只需要买入度为 的节点。如果全都能买,那么有解,输出费用即可。如果某些点不能买,说明无解,然后跑一遍搜索:
以所有能买的节点为起点进行搜索,所有搜不到的节点的最小编号就是第二问答案:
代码实现较为复杂,请耐心调。
#include<bits/stdc++.h> using namespace std; int n,p,m,a,b,pt[3030],c[3030],f[3030],g[3030],r[3030],vis[3030],ans,mn=10000000,te; int l[3030],d[3030],in[3030],s[3030],h,t; vector<int> e[3030],k[3030]; priority_queue<int> q[3030]; stack<int> st; void tarj(int u){ l[u]=d[u]=++h; st.push(u); in[u]=1; for(int i=0;i<int(e[u].size());i++){ int v=e[u][i]; if(!d[v]){ tarj(v); l[u]=min(l[u],l[v]); } else if(in[v]) l[u]=min(l[u],d[v]); } if(l[u]==d[u]){ t++; while(1){ s[st.top()]=t; in[st.top()]=0; if(st.top()==u){ st.pop(); break; } st.pop(); } } } void dfs(int u){ if(vis[u]) return ; vis[u]=1; for(int i=0;i<int(k[u].size());i++){ int v=k[u][i]; dfs(v); } } int main(){ memset(c,0x3f3f3f,sizeof(c)); memset(f,0x3f3f3f,sizeof(f)); memset(g,0x3f3f3f,sizeof(g)); ios::sync_with_stdio(0); cin>>n>>p; for(int i=1;i<=p;i++){ cin>>a>>b; c[a]=b; } cin>>m; for(int i=1;i<=m;i++){ cin>>a>>b; e[a].push_back(b); } for(int i=1;i<=n;i++){ if(!d[i]) tarj(i); } for(int i=1;i<=n;i++){ f[s[i]]=min(f[s[i]],c[i]); g[s[i]]=min(g[s[i]],i); } for(int i=1;i<=n;i++){ if(c[i]<c[0]) r[s[i]]=1; } for(int i=1;i<=n;i++){ for(int j=0;j<int(e[i].size());j++){ if(s[i]!=s[e[i][j]]){ q[s[i]].push(s[e[i][j]]); } } } n=t; for(int i=1;i<=n;i++){ while(!q[i].empty()){ te=q[i].top(); k[i].push_back(te); pt[te]++; while(!q[i].empty()){ if(q[i].top()==te) q[i].pop(); else break; } } } for(int i=1;i<=n;i++){ if(r[i]) dfs(i); } for(int i=1;i<=n;i++){ if(pt[i]==0){ if(r[i]==0){ ans=-1; break; } ans+=f[i]; } } if(ans>=0){ cout<<"YES\n"<<ans; return 0; } for(int i=1;i<=n;i++){ if(vis[i]==0) mn=min(mn,g[i]); } cout<<"NO\n"<<mn; }
- 1
Information
- ID
- 97
- Time
- 1000ms
- Memory
- 512MiB
- Difficulty
- 9
- Tags
- # Submissions
- 23
- Accepted
- 2
- Uploaded By