Meeting HDU - 5521
题意:
一共有n个点,有m个块,每个块内有Si个点,块内点彼此到达费用为wi,两个人分别位于1和n号块,两者同时出发问最短时间遇到是多少?在哪些地方可以遇到?
ΣSi<=106
题解:
题意很明确,我们需要先建边,然后从点1开始跑最短路得到dis[i],再从点n跑最短路得到dist[i]
dis[i]表示第1个点到第i个点的最短距离
dist[i]表示第n个点到第i个点的最短距离
答案就是minn= min(max(dis[i],dist[i]),minn)
因为两者同时出发,所以时间取长者,然后找最短时间所以取min
题目难度在于ΣSi<=106,如果你按照块内所有点两两建边,那复杂度肯定暴力。(考虑极端情况所有点在一个块内),那怎么解决?我们可以在块外建议一个新点x,让块内所有点与其相连,边权不变,这样任意两个点都可以通过这个x中间点实现连接,这样就巧妙建边(会网络流的应该好理解,相当于一个人造源点)
建议不要用ios::sync_with_stdio(0);玄学错误,导致我wa了八次
代码:
#include <bits/stdc++.h>
using namespace std;
#define asd cout<<" SB "<<endl;
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
const int maxn=1e6+9;
struct node{int v;int c;node(int v=0,int c=0):v(v),c(c){}bool operator<(const node &r)const{return c>r.c;}
};
struct cmp{int x;cmp(int x=0):x(x){}bool operator<(const cmp &r)const{return x>r.x;}
};
struct Edge{int v,cost;Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[maxn];
bool vis[maxn];
int dist[maxn];
int dis[maxn];
void dij(int n,int start){memset(vis,0,sizeof(vis));for(int i=1;i<=n;i++)dist[i]=INF;priority_queue<node>q;while(!q.empty())q.pop();dist[start]=0;q.push(node(start,0));node tmp;while(!q.empty()){tmp=q.top();q.pop();int u=tmp.v;if(vis[u])continue;vis[u]=1;for(int i=0;i<E[u].size();i++){int v=E[tmp.v][i].v;int cost=E[u][i].cost;if(!vis[v]&&dist[v]>dist[u]+cost){dist[v]=dist[u]+cost;q.push(node(v,dist[v]));}}}
}
int main(){ios::sync_with_stdio(0);int t;cin>>t;int cas=0;while(t--){memset(E,0,sizeof(E));int n,m;cin>>n>>m;
// for(int i=1;i<=n;i++)dis[i]=INF;int tot=0;for(int i=1;i<=m;i++){int w;cin>>w;int S;cin>>S;for(int j=1;j<=S;j++){int x;cin>>x;// printf("u=%d v=%d w=%d\n",n+i,x,w);E[n+i].push_back(Edge(x,w));E[x].push_back(Edge(n+i,w));}}
// for(int i=n+1;i<=n+m;i++){
// for(int j=i+1;j<=n+m;j++){
// printf("u=%d v=%d w=%d\n",i,j,0);
// E[i].push_back(Edge(j,0));
// E[j].push_back(Edge(i,0));
// }
// }dij(n+m,1);for(int i=1;i<=n;i++)dis[i]=dist[i];dij(n+m,n);int minn=INF;for(int i=1;i<=n;i++)minn=min(minn,max(dis[i],dist[i]));if(minn==INF){printf("Case #%d: Evil John\n",++cas);continue;}priority_queue<cmp>q;for(int i=1;i<=n;i++){if(max(dis[i],dist[i])==minn){q.push(i);}}bool f=0;printf("Case #%d: %d\n",++cas,minn/2);while(!q.empty()){if(f==0)printf("%d",q.top().x);else printf(" %d",q.top().x);q.pop();f=1;}printf("\n");}return 0;
}
/*
2
5 4
1 3 1 2 3
2 2 3 4
3 2 1 5
3 3 3 4 5
3 1
1 2 1 2
*/