标签:
题目地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=5521
思路:边数太多,不能直接建图。对于每个集合,设置一个虚拟点,对于每个集合中的点u:连一条u->S权值为0的边(点在集合中,花费为0);连一条S->u权值为w的边(从集合中一点到另一点花费w)。分别计算从点1到i和从点n到i的最短路,枚举i,则ans=min( ans,max ( dist[0][i],dist[1][i] ) )。
#include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define debu using namespace std; typedef long long LL; const LL INF=1e9; const int maxn=2e5+50; struct Node { int v; LL w; Node(int v=0,LL w=0):v(v),w(w) {} }; int n,m; int v[maxn]; queue<int> q; vector<int> Ans; LL dist[2][maxn]; vector<Node> g[maxn]; void solve(int id,int s) { memset(v,0,sizeof(v)); while(!q.empty()) q.pop(); for(int i=0; i<=n+m+1; i++) dist[id][i]=INF; dist[id][s]=0,q.push(s),v[s]=1; while(!q.empty()) { int now=q.front(); q.pop(),v[now]=0; for(int i=0; i<g[now].size(); i++) { int nt=g[now][i].v; if(dist[id][nt]>dist[id][now]+g[now][i].w) { dist[id][nt]=dist[id][now]+g[now][i].w; if(!v[nt]) { v[nt]=1; q.push(nt); } } } } } int main() { #ifdef debug freopen("in.in","r",stdin); #endif // debug int t,cas=0; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=0;i<=n+m;i++) g[i].clear(); for(int i=1; i<=m; i++) { int k,w; scanf("%d%d",&w,&k); for(int j=1; j<=k; j++) { int x; scanf("%d",&x); g[x].push_back(Node(i+n,0)); g[i+n].push_back(Node(x,w)); } } solve(0,1),solve(1,n); LL ans=INF; Ans.clear(); for(int i=1; i<=n; i++) ans=min(ans,max(dist[0][i],dist[1][i])); for(int i=1; i<=n; i++) if(ans==max(dist[0][i],dist[1][i])) Ans.push_back(i); if(ans==INF) printf("Case #%d: Evil John\n",++cas); else { printf("Case #%d: %d\n",++cas,ans); for(int i=0; i<Ans.size()-1; i++) printf("%d ",Ans[i]); printf("%d\n",Ans[Ans.size()-1]); } } return 0; }
标签:
原文地址:http://blog.csdn.net/wang2147483647/article/details/52253996