HDU 2306 Kingdom

 
Problem 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
 
题目大意:
 
给个有向图,其中有两个点A、B,再给你K个警察,每个人可以守一条边(可以站在边上的任意一个位置),要求从A到B必须要经过至少一个警察,问你max(所有警察max(到A点的距离,到B点的距离))最小是多少。
 
初始思路:
 
使最大值最小=>所以尝试二分。
 
A到B必须经过警察=>即警察所占的边构成一个割集,把AB分开。
 
一旦某个警察占据了一条边,那么他max(到A点的距离,到B点的距离)也可定下来且这个数值仅跟这条边有关,也就是说每条边对应一个值,记为val。
 
进一步思路:
 
二分答案,边权值val大于二分值的边不能选来让警察占据,那问题就转变成用其余的边把AB点分开至少需要几条边,如果边数小于等于给定的警察数,则可行。
 
把不能选的边容量无穷,其余边容量为1,从A到B或B到A跑遍最大流即可解此问题。
 
另:每条边对应的那个值val我是枚举每种情况来求(警察从这条边上到A/B是通过端点u/v,共4种情况)。
 
#include<iostream>
#define INF 1000000000
#define lINF 400000
const int pN=200,eN=20000;
int f_min(int x,int y){
	return x<y?x:y;
}
int f_max(int x,int y){
	return x>y?x:y;
}
int f_min(int a,int b,int c,int d){
	return f_min(f_min(a,b),f_min(c,d));
}
struct Edge{
	int u,v,next;
	int w,l;
};
Edge edge[eN];
int en,head[pN],cur[pN],ps[pN],dep[pN];
void insert(int u,int v,int l){
	edge[en].u=u;
	edge[en].v=v;
	edge[en].l=l;
	edge[en].next=head[u];
	head[u]=en++;
	edge[en].u=v;
	edge[en].v=u;
	edge[en].l=l;
	edge[en].next=head[v];
	head[v]=en++;
}
int max_flow(int n,int s,int t){
	typec tr,res=0;
	int i,j,k,f,r,top;
	while(1){
		memset(dep,-1,n*sizeof(int));
		for(f=dep[ps[0]=s]=0,r=1;f!=r;)
			for(i=ps[f++],j=head[i];j!=-1;j=edge[j].next){
				if(edge[j].w&&-1==dep[k=edge[j].v]){
					dep[k]=dep[i]+1;
					ps[r++]=k;
					if(k==t){
						f=r;
						break;
					}
				}
			}
			if(-1==dep[t])break;
			memcpy(cur,head,n*sizeof(int));
			for(i=s,top=0;;){
				if(i==t){
					for(k=0,tr=INF;k<top;++k)
						if(edge[ps[k]].w<tr)
							tr=edge[ps[f=k]].w;
						for(k=0;k<top;++k)
							edge[ps[k]].w-=tr,edge[ps[k]^1].w+=tr;
						res+=tr;
						i=edge[ps[top=f]].u;
				}
				for(j=cur[i];cur[i]!=-1;j=cur[i]=edge[cur[i]].next)
					if(edge[j].w&&dep[i]+1==dep[edge[j].v])break;
					if(cur[i]!=-1){
						ps[top++]=cur[i];
						i=edge[cur[i]].v;
					}else{
						if(0==top)break;
						dep[i]=-1;
						i=edge[ps[--top]].u;
					}
			}
	}
	return res;
}
int N,K,M;
int tran(int x){
	if(x==95050)return N-2;
	if(x==104729)return N-1;
	return x;
}
int diss[200],dise[200];
void get_data(){
	scanf("%d%d",&K,&M);
	int u,v,l;
	memset(head,-1,sizeof(head));en=0;
	N+=2;
	while(M--){
		scanf("%d%d%d",&u,&v,&l);
		u=tran(u);
		v=tran(v);
		insert(u,v,l);
	}
}
int que[100000],qhead,qtail;
bool inque[200];
void spfa(int x[200],int s){
	int u,v,i;
	for(i=0;i<N;i++)x[i]=INF;
	qhead=qtail=0;
	memset(inque,0,sizeof(inque));
	inque[s]=1;x[s]=0;
	que[qtail++]=s;
	while(qtail>qhead){
		u=que[qhead++];inque[u]=0;
		for(i=head[u];i!=-1;i=edge[i].next){
			v=edge[i].v;
			if(x[v]>x[u]+edge[i].l){
				x[v]=x[u]+edge[i].l;
				if(!inque[v]){
					inque[v]=1;
					que[qtail++]=v;
				}
			}
		}
	}
}
void f_swap(int &a,int &b){
	int t=a;
	a=b;
	b=t;
}
int cal(int l1,int l2,int v){
	if(l1>l2)f_swap(l1,l2);
	if(l1+v<=l2)return l2*2;
	return l1+v+l2;
}
int get_w(int i){
	int s1,s2,e1,e2,temp;
	s1=diss[edge[i].u];s2=diss[edge[i].v];
	e1=dise[edge[i].u];e2=dise[edge[i].v];
	temp=f_min(2*f_max(s1,e1),2*f_max(s2,e2));
	temp=f_min(temp,cal(s1,e2,edge[i].l));
	temp=f_min(temp,cal(s2,e1,edge[i].l));
	return temp;
}
void get_dis_w(){
	spfa(diss,N-2);
	spfa(dise,N-1);
	int i;
	for(i=0;i<en;i+=2){
		edge[i].l=get_w(i);
//		printf("%d *\n",edge[i].l);
		edge[i^1].l=edge[i].l;
	}
}
bool ok(int lim){
	int i;
//	printf("%d lim\n",lim);
	for(i=0;i<en;i+=2){
		if(edge[i].l<=lim){
//			printf("%d %d %d\n",edge[i].l,edge[i].u,edge[i].v);
			edge[i].w=edge[i^1].w=1;
		}else{
			edge[i].w=edge[i^1].w=lINF;
		}
	}
	int temp=max_flow(N,N-2,N-1);
	if(temp>K)return 0;
	return 1;
}
void run(){
	get_dis_w();
	int h,l,mid;
	h=200000;l=0;
	while(h>l){
		mid=(h+l)>>1;
		if(ok(mid))h=mid;
		else l=mid+1;
	}
	if(h==200000)printf("Impossible\n");
	else printf("%.1lf\n",h*0.5);
}
int main(){
	while(scanf("%d",&N),N){
		get_data();
		run();
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值