果然还是应该先看下胡伯涛的论文……
orz proverbs
题意:
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了N次T_T,直接从S进行dfs,对于左边的点,如果走不到则表明 s->i 这条边被割掉了,对于右边的点,如果走的到则表明 i+n->t 这条边被割掉了,因为如果没割掉就直接从这个点走到t了……唉我一开始居然没想到
1 Source Code 2 Problem: 2125 User: sdfzyhy 3 Memory: 848K Time: 79MS 4 Language: G++ Result: Accepted 5 6 Source Code 7 8 //BZOJ 2125 9 #include<vector> 10 #include<cstdio> 11 #include<cstring> 12 #include<cstdlib> 13 #include<iostream> 14 #include<algorithm> 15 #define rep(i,n) for(int i=0;i<n;++i) 16 #define F(i,j,n) for(int i=j;i<=n;++i) 17 #define D(i,j,n) for(int i=j;i>=n;--i) 18 #define fore(i,x) for(int i=head[x];i;i=next[i]) 19 #define pb push_back 20 using namespace std; 21 inline int getint(){ 22 int v=0,sign=1; char ch=getchar(); 23 while(ch<‘0‘||ch>‘9‘){ if (ch==‘-‘) sign=-1; ch=getchar();} 24 while(ch>=‘0‘&&ch<=‘9‘){ v=v*10+ch-‘0‘; ch=getchar();} 25 return v*sign; 26 } 27 const int N=310,M=20010,INF=~0u>>2; 28 typedef long long LL; 29 /******************tamplate*********************/ 30 31 struct edge{ 32 int from,to,v; 33 }; 34 int n,m; 35 struct Net{ 36 edge E[M]; 37 int head[N],next[M],cnt; 38 void add(int x,int y,int z){ 39 E[++cnt]=(edge){x,y,z}; 40 next[cnt]=head[x]; head[x]=cnt; 41 E[++cnt]=(edge){y,x,0}; 42 next[cnt]=head[y]; head[y]=cnt; 43 } 44 int s,t,d[N],cur[N],Q[N]; 45 void init(){ 46 n=getint(); m=getint(); 47 s=0; t=n*2+1; cnt=1; 48 int x,y; 49 F(i,1,n){ 50 x=getint(); 51 add(i+n,t,x); 52 } 53 F(i,1,n){ 54 x=getint(); 55 add(s,i,x); 56 } 57 F(i,1,m){ 58 x=getint(); y=getint(); 59 add(x,y+n,INF); 60 } 61 } 62 bool mklevel(){ 63 memset(d,-1,sizeof d); 64 d[s]=0; 65 int l=0,r=-1; 66 Q[++r]=s; 67 while(l<=r){ 68 int x=Q[l++]; 69 fore(i,x){ 70 edge&e=E[i]; 71 if (d[e.to]==-1 && e.v>0){ 72 d[e.to]=d[x]+1; 73 Q[++r]=e.to; 74 } 75 } 76 } 77 return d[t]!=-1; 78 } 79 int dfs(int x,int a){ 80 if (x==t) return a; 81 int flow=0; 82 for(int &i=cur[x];i && flow<a;i=next[i]){ 83 edge&e=E[i]; 84 if (!e.v || d[e.to]!=d[x]+1) continue; 85 int f=dfs(e.to,min(a-flow,e.v)); 86 if (f>0){ 87 flow+=f; 88 e.v-=f; 89 E[i^1].v+=f; 90 } 91 } 92 if (!flow) d[x]=-1; 93 return flow; 94 } 95 int Dinic(){ 96 int flow=0; 97 while(mklevel()){ 98 F(i,s,t) cur[i]=head[i]; 99 flow+=dfs(s,INF); 100 } 101 return flow; 102 } 103 bool vis[N]; 104 void dfs1(int x){ 105 if (vis[x]) return; 106 vis[x]=1; 107 for(int i=head[x];i;i=next[i]) 108 if (E[i].v) dfs1(E[i].to); 109 } 110 void solve(){ 111 printf("%d\n",Dinic()); 112 int num=0; 113 memset(vis,0,sizeof vis); 114 dfs1(s); 115 F(i,1,n) num+=(!vis[i])+vis[i+n]; 116 printf("%d\n",num); 117 F(i,1,n){ 118 if (!vis[i]) printf("%d -\n",i); 119 if (vis[i+n]) printf("%d +\n",i); 120 } 121 } 122 }G1; 123 124 int main(){ 125 #ifndef ONLINE_JUDGE 126 freopen("2125.in","r",stdin); 127 freopen("2125.out","w",stdout); 128 #endif 129 G1.init(); 130 G1.solve(); 131 return 0; 132 }
【POJ】【2125】Destroying the Graph
原文:http://www.cnblogs.com/Tunix/p/4335741.html