标签:目的 sum amp 经营 金融 esc hint space bzoj
约定:
2 <= N <= 50
1 <= M <= 2450
1 <= T <= 50
1 <= X,Y <= N
X != Y
1 <= Z <= 50
题解:我们假设在tim时所有人都能到达终点,于是我们枚举tim,将每个点拆成tim个,然后连边跑最大流,若流量=T,说明tim就是答案
具体方法:用(i,j)表示将原来的i号节点拆成第j个点
1.S -> (0,0) 流量T
2.(i,j-1) -> (i,j) 流量∞
3.对于边(a,b,c) (a,j-1) -> (b,j) 流量c
4.(n,j) -> T 流量T
由于本人觉得点数比较多,感到很虚,所以用了动态加边的最大流,56ms飞起~
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define P(A,B) ((B)*n+A) using namespace std; int to[1000000],next[1000000],val[1000000],d[50010],head[50010],pa[2500],pb[2500],pc[2500]; int n,m,t,cnt,ans,sum,S,T,tim; queue<int> q; int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } void add(int a,int b,int c) { to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } int bfs() { int i,u; memset(d,0,sizeof(d)); while(!q.empty()) q.pop(); d[S]=1,q.push(S); while(!q.empty()) { u=q.front(),q.pop(); for(i=head[u];i!=-1;i=next[i]) { if(!d[to[i]]&&val[i]) { d[to[i]]=d[u]+1; if(to[i]==T) return 1; q.push(to[i]); } } } return 0; } int dfs(int x,int mf) { if(x==T) return mf; int i,temp=mf,k; for(i=head[x];i!=-1;i=next[i]) { if(d[to[i]]==d[x]+1&&val[i]) { k=dfs(to[i],min(temp,val[i])); if(!k) d[to[i]]=0; val[i]-=k,val[i^1]+=k,temp-=k; if(!temp) break; } } return mf-temp; } int main() { n=rd(),m=rd(),t=rd(),tim=n+t; S=0,T=n*(tim+1)+1; memset(head,-1,sizeof(head)); add(S,1,t); int i,j,k,a,b,c; for(i=1;i<=m;i++) pa[i]=rd(),pb[i]=rd(),pc[i]=rd(); for(i=1;i<=tim;i++) { for(j=1;j<=m;j++) add(P(pa[j],i-1),P(pb[j],i),pc[j]); for(j=1;j<=n;j++) add(P(j,i-1),P(j,i),1<<30); add(P(n,i),T,t); while(bfs()) sum+=dfs(S,1<<30); if(sum==t) { printf("%d",i); return 0; } } }
【BZOJ1570】[JSOI2008]Blue Mary的旅行 动态加边网络流
标签:目的 sum amp 经营 金融 esc hint space bzoj
原文地址:http://www.cnblogs.com/CQzhangyu/p/6855711.html