标签:左右 ++ limit com gis flow return rate ble
Time Limit: 2000MS | Memory Limit: 65536K | |||
Total Submissions: 8198 | Accepted: 2635 | Special Judge |
Description
Input
Output
Sample Input
3 6 1 2 3 4 2 1 1 2 1 1 3 2 1 2 3 1 2 3
Sample Output
5 3 1 + 2 - 2 +
Source
【题意】:
N个点M条边的有向图,给出如下两种操作。
删除点i的所有出边,代价是Ai。
删除点j的所有入边,代价是Bj。
求最后删除图中所有的边的最小代价。
其实就是二分图最小点权覆盖。
定义:从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。
//最小点权覆盖就是求最小割(证明可参考胡伯涛论文“最小割模型在信息学竞赛中的应用”)。
【题解】:
拆点。n个点拆成2n个点(左右各n个,i与(i+n)对应,之间连容量INF的边),S和i连容量为Ai的边,(i+n)与T之间连容量为Bi的边,求最小割即可
这样做为什么对呢?
当一条边存在的条件就是网络中还存在从S到T的非满流边!
方案输出不多说。
//输出方案WA到挺的代码 #include<cstdio> #include<cstring> #include<algorithm> #define R register #define inf 0x3f3f3f3f using namespace std; int read(){ R int x=0;bool f=1; R char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=0;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();} return f?x:-x; } const int N=1e5+10; struct node{ int v,next,cap,flow; }e[N<<2];int tot=1; struct data{ int x,op,val; bool operator <(const data &a)const{ return val==a.val?x<a.x:val<a.val; } }record[N]; int n,m,cs,cc,S,T,a[N],b[N],cur[N],head[N],dis[N],q[N*2]; bool mark[N]; void add(int x,int y,int z){ e[++tot].v=y;e[tot].next=head[x];e[tot].cap=z;e[tot].flow=0;head[x]=tot; e[++tot].v=x;e[tot].next=head[y];e[tot].cap=0;e[tot].flow=0;head[y]=tot; } bool bfs(){ int h=0,t=1; memset(dis,-1,sizeof(dis)); dis[S]=0;q[1]=S; while(h!=t){ int x=q[++h]; for(int i=head[x];i;i=e[i].next){ int v=e[i].v; if(dis[v]==-1&&e[i].cap>e[i].flow){ dis[v]=dis[x]+1; q[++t]=v; } } } return dis[T]!=-1; } int dfs(int x,int f){ if(x==T||!f) return f; int used=0,f1; for(int &i=cur[x];i;i=e[i].next){ if(dis[x]+1==dis[e[i].v]&&(f1=dfs(e[i].v,min(f,e[i].cap-e[i].flow)))>0){ e[i].flow+=f1;e[i^1].flow-=f1; used+=f1;f-=f1; if(!f) break; } } return used; } int dinic(){ int ans=0; while(bfs()){ for(int i=S;i<=T;i++) cur[i]=head[i]; ans+=dfs(S,0x7fffffff); } return ans; } void dfs_cut(int x){ if(x==T) return ; mark[x]=1; for(int i=head[x];i;i=e[i].next){ int v=e[i].v,val,op; if(!mark[v]){ if(e[i].cap==e[i].flow){ if(x!=S){ if(x>n) op=0,val=b[x-n]; else op=1,val=a[x]; record[++cc].x=x;record[cc].op=op;record[cc].val=val; } if(v!=T){ if(v>n) op=0,val=b[v-n]; else op=1,val=a[v]; record[++cc].x=v;record[cc].op=op;record[cc].val=val; } } dfs_cut(v); } } } int main(){ n=read();m=read(); S=0;T=n<<1|1; for(int i=1;i<=n;i++) a[i]=read(),add(S,i,a[i]); for(int i=1;i<=n;i++) b[i]=read(),add(i+n,T,b[i]); for(int i=1,x,y;i<=m;i++) x=read(),y=read(),add(x,y+n,inf); printf("%d\n",dinic()); dfs_cut(S); for(int i=1;i<=n;i++){ if(!mark[i]) cs++; if(mark[i+n]) cs++; } printf("%d\n",cs); for(int i=1;i<=cc;i++) if(record[i].x>n) record[i].x-=n; sort(record+1,record+cc+1); for(int i=1;i<=cs;i++){ int &x=record[i].x,&y=record[i].op; printf("%d ",x);putchar(y?‘+‘:‘-‘);printf("\n"); } return 0; } //from zjk‘s AC code #include<cstdio> #include<iostream> #define N 210 #define M 5010 #define inf 1000000000 using namespace std; int a[N],b[N],head[N],dis[N],q[N],vis[N],n,m,cnt=1,S,T; struct node{ int v,f,pre; }e[M*2]; void add(int u,int v,int f){ e[++cnt].v=v;e[cnt].f=f;e[cnt].pre=head[u];head[u]=cnt; e[++cnt].v=u;e[cnt].f=0;e[cnt].pre=head[v];head[v]=cnt; } bool bfs(){ for(int i=1;i<=T;i++)dis[i]=inf; int h=0,t=1;q[1]=S;dis[S]=0; while(h<t){ int u=q[++h]; for(int i=head[u];i;i=e[i].pre){ int v=e[i].v; if(e[i].f&&dis[u]+1<dis[v]){ dis[v]=dis[u]+1; if(v==T)return true; q[++t]=v; } } } if(dis[T]==inf)return false; return true; } int dinic(int now,int f){ if(now==T)return f; int rest=f; for(int i=head[now];i;i=e[i].pre){ int v=e[i].v; if(e[i].f&&dis[v]==dis[now]+1){ int t=dinic(v,min(rest,e[i].f)); if(!t)dis[v]=0; e[i].f-=t; e[i^1].f+=t; rest-=t; } } return f-rest; } void dfs(int x){ vis[x]=1; for(int i=head[x];i;i=e[i].pre){ if(!e[i].f||vis[e[i].v])continue; dfs(e[i].v); } } int main(){ scanf("%d%d",&n,&m); S=0,T=2*n+1; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); add(i+n,T,a[i]); } for(int i=1;i<=n;i++){ scanf("%d",&b[i]); add(S,i,b[i]); } for(int i=1;i<=m;i++){ int x,y;scanf("%d%d",&x,&y); add(x,y+n,inf); } int min_cnt=0,p=0,pin=0,pout=0; while(bfs()) min_cnt+=dinic(S,inf); printf("%d\n",min_cnt); dfs(S); for(int i=1;i<=n;i++){ if(!vis[i])p++; if(vis[i+n])p++; } printf("%d\n",p); for(int i=1;i<=n;i++){ if(!vis[i])printf("%d -\n",i); if(vis[i+n])printf("%d +\n",i); } return 0; }
POJ 2125 Destroying the Graph 二分图最小点权覆盖
标签:左右 ++ limit com gis flow return rate ble
原文地址:http://www.cnblogs.com/shenben/p/6258651.html