bzoj 2324: [ZJOI2011]营救皮卡丘
2018-01-03 19:42
323 查看
题意:
皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路。火箭队一共有N个据点,据点之间存在M条双向道路。据点分别从1到N标号。小智一行K人从真新镇出发,营救被困在N号据点的皮卡丘。为了方便起见,我们将真新镇视为0号据点,一开始K个人都在0号点。
由于火箭队的重重布防,要想摧毁K号据点,必须按照顺序先摧毁1到K-1号据点,并且,如果K-1号据点没有被摧毁,由于防御的连锁性,小智一行任何一个人进入据点K,都会被发现,并产生严重后果。因此,在K-1号据点被摧毁之前,任何人是不能够经过K号据点的。
为了简化问题,我们忽略战斗环节,小智一行任何一个人经过K号据点即认为K号据点被摧毁。被摧毁的据点依然是可以被经过的。
K个人是可以分头行动的,只要有任何一个人在K-1号据点被摧毁之后,经过K号据点,K号据点就被摧毁了。显然的,只要N号据点被摧毁,皮卡丘就得救了。
野外的道路是不安全的,因此小智一行希望在摧毁N号据点救出皮卡丘的同时,使得K个人所经过的道路的长度总和最少。
请你帮助小智设计一个最佳的营救方案吧!
题解:
可以先做这题:bzoj 1927这题也可以用同样的方法做下限,floyd建边。
接着考虑先后顺序的问题。
假设当前想从i走到j,显然只能走比i或j小的点,那么就floyd的时候加多一个限制就可以了。
具体建边:
设i为入点,i’为出点。
st->1’~n’ 流量1,费用0。
1~n->ed 流量1,费用0。
st->0’ 流量k,费用0(代表k个人)
i’->j 流量1,费用dis[i][j]。
code:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> const int inf=1<<29; using namespace std; struct node{ int x,y,c,d,next,other; }a[2110000];int len=0,last[1100]; int s[10005],p[10005],q[10005],st,ed; bool u[10005]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void ins(int x,int y,int c,int d) { int k1=++len; a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d; a[len].next=last[x];last[x]=len; int k2=++len; a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1; } bool spfa() { memset(s,63,sizeof(s)); memset(u,false,sizeof(u)); int l=1,r=2;q[l]=st;s[st]=0;u[st]=true; while(l!=r) { int x=q[l]; for(int i=last[x];i;i=a[i].next) { int y=a[i].y; if(s[y]>s[x]+a[i].d&&a[i].c>0) { s[y]=s[x]+a[i].d; p[y]=i; if(!u[y]) { u[y]=true; q[r]=y; r++;if(r>ed+1) r=1; } } } u[x]=false; l++;if(l>ed+1) l=1; } return s[ed]<999999999; } int flow() { int x=ed; int ans=0,min=-1; while(x!=st) { int i=p[x]; if (a[i].c<min||min==-1)min=a[i].c; x=a[i].x; } x=ed; while(x!=st) { int i=p[x]; a[i].c-=min; a[a[i].other].c+=min; x=a[i].x; ans=ans+a[i].d*min; } return ans; } int n,m,k,dis[160][160]; void floyd() { for(int k=0;k<=n;k++) for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) if((k<=i||k<=j)&&dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j]; } int main() { n=read();m=read();k=read(); st=2*n+2;ed=st+1; for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) if(i!=j) dis[i][j]=inf; for(int i=1;i<=m;i++) { int x,y,c;x=read();y=read();c=read(); dis[x][y]=dis[y][x]=min(dis[x][y],c); } floyd(); for(int i=1;i<=n;i++) { ins(st,i+n+1,1,0); ins(i,ed,1,0); } ins(st,n+1,k,0); for(int i=0;i<=n;i++) for(int j=i+1;j<=n;j++) if(dis[i][j]!=inf) ins(i+n+1,j,1,dis[i][j]); int ans=0; while(spfa()) ans+=flow(); printf("%d",ans); }
相关文章推荐
- [省选前题目整理][BZOJ 2324][ZJOI 2011]营救皮卡丘(费用流)
- [最小费用最大流] BZOJ2324: [ZJOI2011]营救皮卡丘
- 【bzoj2324】[ZJOI2011]营救皮卡丘 最短路-Floyd+有上下界费用流
- bzoj2324 [ZJOI2011]营救皮卡丘
- [最小权路径覆盖 & 网络流] BZOJ2324 :[ZJOI2011] 营救皮卡丘
- 【BZOJ 2324】[ZJOI2011]营救皮卡丘 费用流
- BZOJ 2324: [ZJOI2011]营救皮卡丘( floyd + 费用流 )
- BZOJ2324: [ZJOI2011]营救皮卡丘
- BZOJ2324[ZJOI2011]营救皮卡丘
- [BZOJ2324][ZJOI2011][最小费用最大流]营救皮卡丘
- Bzoj2324 [ZJOI2011]营救皮卡丘
- bzoj2324[ZJOI2011]营救皮卡丘
- BZOJ2324 [ZJOI2011]营救皮卡丘 【费用流】
- BZOJ 2324: [ZJOI2011]营救皮卡丘(带上下限的最小费用最大流)
- BZOJ2324: [ZJOI2011]营救皮卡丘
- BZOJ2324 [ZJOI2011]营救皮卡丘
- 【BZOJ2324】[ZJOI2011]营救皮卡丘 有上下界费用流
- BZOJ 2324 [ZJOI2011] 营救皮卡丘
- bzoj 2324 [ZJOI2011]营救皮卡丘(floyd,费用流)
- [bzoj2324][ZJOI2011]营救皮卡丘 上下界费用流+floyd