您的位置:首页 > 理论基础 > 计算机网络

Poj2638 网络流+最短路+二分答案

2013-10-07 13:37 1001 查看
= = 图论的题目使用的算法一多起来调试就变得好烦啊。。。还是要多用模板来解决问题。。。

题目内容懒得翻译了。。。。。。 直接贴上来。。。

Description


King Kong is the feared but fair ruler of Transylvania. The kingdom consists of two cities and N < 150 towns, with nonintersecting roads between some of them. The roads are bidirectional, and
it takes the same amount of time to travel them in both directions. Kong has G < 353535 soldiers. 

Due to increased smuggling of goat cheese between the two cities, Kong has to place his soldiers on some of the roads in such a way that it is impossible to go from one city to the other without passing a soldier. The soldiers must not be placed inside a town,
but may be placed on a road, as close as Kong wishes, to any town. Any number of soldiers may be placed on the same road. However, should any of the two cities be attacked by a foreign army, the king must be able to move all his soldiers fast to the attacked
city. Help him place the soldiers in such a way that this mobilizing time is minimized. 

Note that the soldiers cannot be placed in any of the cities or towns. The cities have ZIP-codes 95050 and 104729, whereas the towns have ZIPcodes from 0 to N - 1. There will be at most one road between any given pair of towns or cities.
Input

The input contains several test cases. The first line of each test case is N, G and E, where N and G are as defined above and E < 5000 is the number of roads. Then follow E lines, each of which contains three integers: A and B, the ZIP codes of the endpoints,
and φ, the time required to travel the road,φ < 1000. The last line of the input is a line containing a single 0.
Output

For each test case in the input, print the best mobilizing time possible, with one decimal. If the given number of soldiers is not enough to stop the goat cheese, print "Impossible" instead.
Sample Input
4 2 6
95050 0 1
0 1 2
1 104729 1
95050 2 1
2 3 3
3 104729 1
4 1 6
95050 0 1
0 1 2
1 104729 1
95050 2 1
2 3 3
3 104729 1
4 2 7
95050 0 1
0 1 2
1 104729 1
95050 2 1
2 3 3
3 104729 1
2 1 5
0

Sample Output
2.5
Impossible
3.0

Source

Nordic 2005

总之,在任意一条边上布置的士兵的召回所需时间可以预处理出来(需要求一下最短路)之后对时间二分答案,求一个最小割,如果割边数<=G 就代表有解。。

尼玛 一开始用的模板是错的搞得各种蛋疼OTZ

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn=200;
const int maxm=6000;
const int inf=100000008;

struct edge{
int u,v,nxt;
int lg,tim,fl;
}es[maxm*2+10];
//Index of es starts from 2

int n,g,m,u,v,p,en;
int s[maxn+10],ds[maxn+10],dt[maxn+10];
bool inq[maxn+10];
int dis[maxn+10],vis[maxn+10];

inline int iabs(int x){
return x>=0?x:-x;
}

void add_edge(int u,int v,int p){
es[++en].u=u;
es[en].v=v;
es[en].lg=p;
es[en].nxt=s[u];
s[u]=en;

es[++en].u=v;
es[en].v=u;
es[en].lg=p;
es[en].nxt=s[v];
s[v]=en;
}

void bfs(int st,int ed){
queue<int> q;
memset(vis,0,sizeof(vis));
vis[st]=1; dis[st]=0;
q.push(st);
while(!q.empty()){
int p=q.front(); q.pop();
for(int i=s[p];i;i=es[i].nxt)
if(es[i].fl && !vis[es[i].v]){
vis[es[i].v]=1;
dis[es[i].v]=dis[p]+1;
q.push(es[i].v);
}
}
}

int dfs(int p,int ed,int cap){
int fl,ans=0;
if(p==ed) return cap;
for(int i=s[p];i && cap;i=es[i].nxt)
if(es[i].fl && (dis[es[i].v]==dis[p]+1)){
fl=dfs(es[i].v,ed,min(es[i].fl,cap));
es[i].fl-=fl; es[i^1].fl+=fl;
cap-=fl; ans+=fl;
}
return ans;
}

int max_flow(int st,int ed){
int ans=0;
while(1){
bfs(st,ed);
if(!vis[ed]) break;
ans+=dfs(st,ed,inf);
if(ans>=inf) break;
}
return ans;
}

void spfa(int *d,int a){
for(int i=0;i<n;i++) d[i]=inf;
memset(inq,0,sizeof(inq));
queue<int> q;
d[a]=0;
inq[a]=1;
q.push(a);
while(!q.empty()){
int p=q.front();
for(int i=s[p];i;i=es[i].nxt)
if(d[p]+es[i].lg<d[es[i].v]){
d[es[i].v]=d[p]+es[i].lg;
if(!inq[es[i].v]){
inq[es[i].v]=1;
q.push(es[i].v);
}
}
q.pop();
inq[p]=0;
}
}

bool judge(int time){
for(int i=2;i<=en;i++)
if(es[i].tim<=time) es[i].fl=1;
else es[i].fl=inf;
int tmp=max_flow(n-2,n-1);

//	printf(" %d :: %d\n",time,tmp);

if(tmp<=g) return 1;
else return 0;
}

int main(){
scanf("%d",&n);
while(n){
scanf("%d%d",&g,&m);
n+=2;
en=1;
memset(s,0,sizeof(s));
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&p);
if(u==95050) u=n-2;
if(u==104729) u=n-1;
if(v==95050) v=n-2;
if(v==104729) v=n-1;
add_edge(u,v,p);
}
spfa(ds,n-2);
spfa(dt,n-1);
for(int i=2;i<=en;i++){
es[i].tim=max(ds[es[i].u],dt[es[i].u])*2;
es[i].tim=min(es[i].tim,max(ds[es[i].v],dt[es[i].v])*2);
if(es[i].lg>=iabs(ds[es[i].u]-dt[es[i].v]))
es[i].tim=min(es[i].tim,ds[es[i].u]+dt[es[i].v]+es[i].lg);
else es[i].tim=min(es[i].tim,max(ds[es[i].u],dt[es[i].v])*2);
if(es[i].lg>=iabs(ds[es[i].v]-dt[es[i].u]))
es[i].tim=min(es[i].tim,ds[es[i].v]+dt[es[i].u]+es[i].lg);
else es[i].tim=min(es[i].tim,max(ds[es[i].v],dt[es[i].u])*2);
}
/*
for(int i=2;i<=en;i++)
printf("%d %d :: %d\n",es[i].u,es[i].v,es[i].tim);
*/
if(!judge(ds[n-1]*2)) printf("Impossible\n");
else{
int l=0,r=ds[n-1]*2;
while(l+1<r){
if(judge((l+r)/2)) r=(l+r)/2;
else l=(l+r)/2;
}
printf("%.1f\n",(double)(r)/2.0);
}
scanf("%d",&n);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息