0x6A 网络流初步
CH Round #17-C
这个算是一个技能点吧,不点不会,点了就没什么了。懒得写看书吧书上的1应该是0。。。
我又回来了太懒了不想翻书还是写写吧
必须边的判定条件:该边流量为0且两端的点在残余网络不在同一个联通分量
可行边的判定条件:该边流量为0或两端的点在残余网络在同一个联通分量
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int inf=(1<<30); struct node { int x,y,c,id,next,other; }a[2100000];int len,last[110000]; void ins(int x,int y,int c,int id) { int k1,k2; len++;k1=len; a[len].x=x;a[len].y=y;a[len].c=c;a[len].id=id; a[len].next=last[x];last[x]=len; len++;k2=len; a[len].x=y;a[len].y=x;a[len].c=0;a[len].id=-1; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1; } int st,ed; int h[110000],list[110000]; bool bt_h() { int head=1,tail=2;list[1]=st; memset(h,0,sizeof(h));h[st]=1; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(h[y]==0&&a[k].c>0) { h[y]=h[x]+1; list[tail++]=y; } } head++; } if(h[ed]==0)return false; return true; } int findflow(int x,int f) { if(x==ed)return f; int s=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&h[y]==h[x]+1&&f>s) { int t=findflow(y,min(a[k].c,f-s)); s+=t;a[k].c-=t;a[a[k].other].c+=t; } } if(s==0)h[x]=0; return s; } //------------------dicnic---------------------- bool b[2100000]; struct enode { int x,y,id,next; }e[2100000];int elen,elast[110000]; void eins(int x,int y,int id) { elen++; e[elen].x=x;e[elen].y=y;e[elen].id=id; e[elen].next=elast[x];elast[x]=elen; } int z,dfn[110000],low[110000]; int top,sta[110000];bool v[110000]; int cnt,bel[110000]; void SCC(int x) { dfn[x]=low[x]=++z; sta[++top]=x;v[x]=true; for(int k=elast[x];k;k=e[k].next) { int y=e[k].y; if(dfn[y]==0) { SCC(y); low[x]=min(low[x],low[y]); } else if(v[y]==true) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { int k;cnt++; do { k=sta[top];top--; v[k]=false; bel[k]=cnt; }while(k!=x); } } int aslen,as[2100000]; int main() { int n,m,T,x,y; scanf("%d%d%d",&n,&m,&T); st=n+m+1,ed=n+m+2; len=0;memset(last,0,sizeof(last)); for(int i=1;i<=T;i++) scanf("%d%d",&x,&y), ins(x,y+n,1,i); for(int i=1;i<=n;i++)ins(st,i,1,-1); for(int i=1;i<=m;i++)ins(i+n,ed,1,-1); int ans=0; while(bt_h()) { ans+=findflow(st,inf); } //----------------------------------------- elen=0;memset(elast,0,sizeof(elast)); memset(b,true,sizeof(b)); for(int i=1;i<=len;i++) { if(a[i].c==0&&a[i].y>n&&a[i].x!=st&&a[i].y!=ed)b[a[i].id]=false; if(a[i].c==1) eins(a[i].x,a[i].y,a[i].id); } z=0,top=0,cnt=0; for(int i=1;i<=n+m+2;i++) if(dfn[i]==0)SCC(i); for(int i=1;i<=elen;i++) if(bel[e[i].x]==bel[e[i].y])b[e[i].id]=false; aslen=0; for(int i=1;i<=T;i++) if(b[i]==true)as[++aslen]=i; printf("%d\n",aslen); for(int i=1;i<aslen;i++)printf("%d ",as[i]); if(aslen!=0)printf("%d\n",as[aslen]); return 0; }
poj1966 不难。拆点,删除一个点相当于把他的两个点之间的边割掉。有趣的是,这题枚举起始点和结束点,意在把这两个点分在不同的集合,使得图不联通。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int inf=(1<<30); struct node { int x,y,c,next,other; }a[41000],e[41000];int len,last[110],elen,elast[110]; void ins(int x,int y,int c) { int k1,k2; len++;k1=len; a[len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[x];last[x]=len; len++;k2=len; a[len].x=y;a[len].y=x;a[len].c=0; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1; } int st,ed; int h[110],list[110]; bool bt_h() { int head=1,tail=2;list[1]=st; memset(h,0,sizeof(h));h[st]=1; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(h[y]==0&&a[k].c>0) { h[y]=h[x]+1; list[tail++]=y; } } head++; } if(h[ed]==0)return false; return true; } int findflow(int x,int f) { if(x==ed)return f; int s=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&h[y]==h[x]+1&&f>s) { int t=findflow(y,min(a[k].c,f-s)); s+=t;a[k].c-=t;a[a[k].other].c+=t; } } if(s==0)h[x]=0; return s; } char ch; void sc(int &x,int &y) { ch=getchar(); while(ch!='(')ch=getchar(); scanf("%d",&x);x++; ch=getchar(); while(ch!=',')ch=getchar(); scanf("%d",&y);y++; ch=getchar(); while(ch!=')')ch=getchar(); } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { len=0;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++)ins(i,i+n,1); for(int i=1;i<=m;i++) { int x,y;sc(x,y); ins(x+n,y,inf);ins(y+n,x,inf); } memcpy(e,a,sizeof(e)); elen=len;memcpy(elast,last,sizeof(elast)); int mmin=inf; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j) { memcpy(a,e,sizeof(a)); len=elen;memcpy(last,elast,sizeof(last)); st=i+n,ed=j; int ans=0; while(bt_h()) { ans+=findflow(st,inf); } mmin=min(ans,mmin); } if(mmin==inf)printf("%d\n",n); else printf("%d\n",mmin); } return 0; }
poj3422 算是套路题吧,拆点后对于一个点的自连,连一条流量为1,费用为点权的边,连一条流量为K-1,费用为0的边。开始我从1,1的出边为起始到n,n的入边,问题在于无法控制只跑K次。天真的我还写了while(K--&&spfa())事实证明这样错得一批
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int inf=(1<<30); struct node { int x,y,c,d,next,other; }a[2100000];int len,last[11000]; void ins(int x,int y,int c,int d) { int k1,k2; len++;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; len++;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; } int ans,st,ed; int list[11000],d[11000],pre[11000],c[11000]; bool v[11000]; bool spfa() { memset(d,63,sizeof(d));d[st]=0; memset(v,false,sizeof(v));v[st]=true; int head=1,tail=2;list[1]=st;c[st]=inf; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&d[y]>d[x]+a[k].d) { d[y]=d[x]+a[k].d; pre[y]=k; c[y]=min(a[k].c,c[x]); if(v[y]==false) { v[y]=true; list[tail++]=y; if(tail==10500)tail=1; } } } v[x]=false; head++;if(head==10500)head=1; } if(d[ed]==d[0])return false; else { ans+=d[ed]*c[ed]; int y=ed; while(y!=st) { int k=pre[y]; a[k].c-=c[ed]; a[a[k].other].c+=c[ed]; y=a[k].x; } return true; } } int n,mp[110][110]; int pt(int x,int y){return n*(x-1)+y;} int main() { int K; scanf("%d%d",&n,&K); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&mp[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i!=n)ins(n*n+pt(i,j),pt(i+1,j),K,0); if(j!=n)ins(n*n+pt(i,j),pt(i,j+1),K,0); ins(pt(i,j),n*n+pt(i,j),1,-mp[i][j]); ins(pt(i,j),n*n+pt(i,j),K-1,0); } st=pt(1,1);ed=n*n+pt(n,n); ans=0; while(spfa()==true); printf("%d\n",-ans); return 0; }
pain and happy in the cruel world.