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

7 篇文章 0 订阅

= = 图论的题目使用的算法一多起来调试就变得好烦啊。。。还是要多用模板来解决问题。。。

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

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


总之,在任意一条边上布置的士兵的召回所需时间可以预处理出来(需要求一下最短路)之后对时间二分答案,求一个最小割,如果割边数<=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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值