您的位置:首页 > 其它

[HDOJ 4940] Destroy Transportation system [最大流]

2014-08-13 15:20 288 查看
给定一个图,整个图一定是一个强联通分量,每个边上有两个非负值d和b,你选定一个点集S,剩余的点构成了集合T,你的收益是所有T到S的边的d+b的和减去所有S到T的边的d的和,问对于任意的点集S,你的收益是否一定是非负的?

对于任意一条边,下界为d,上界为d+b,求无源无汇可行流即可。有可行流,则一定非负;无可行流,则存在一组点集,收益为负的。

#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXINT=~0u>>1;
const int N=210;
const int M=15100;

struct NetWorkFlow {
struct Node {
int fe,h,cur,v;
};
struct Edge {
int t,ne,f;
};
Node a
;
Edge b[M*2];
int d[M];
int s,t,n,p;
void clear(int nn,int ss,int tt) {
n=nn;s=ss;t=tt;
for (int i=0;i<=n;i++) {
a[i].fe=-1;
a[i].v=0;
}
p=0;
}
void putedge(int x,int y,int f) {
b[p].t=y;
b[p].f=f;
b[p].ne=a[x].fe;
a[x].fe=p;
p++;
b[p].t=x;
b[p].f=0;
b[p].ne=a[y].fe;
a[y].fe=p;
p++;
}
bool bfs() {
int i,p,q,j;
for (i=0;i<=n;i++) a[i].h=0;
a[s].h=1;
p=q=0;
d[q++]=s;
while (p<q) {
i=d[p];
for (j=a[i].fe;j!=-1;j=b[j].ne) {
if (a[b[j].t].h==0&&b[j].f>0) {
a[b[j].t].h=a[i].h+1;
if (b[j].t==t) return true;
d[q++]=b[j].t;
}
}
p++;
}
return false;
}
int dfs(int i,int v) {
if (i==t) {
a[t].v+=v;
return v;
}
int ans=0;
for (int &j=a[i].cur;j!=-1;j=b[j].ne) {
if (b[j].f>0&&a[b[j].t].h>a[i].h) {
int tmp=dfs(b[j].t,min(b[j].f,v));
v-=tmp;
b[j].f-=tmp;
b[j^1].f+=tmp;
ans+=tmp;
if (v==0) return ans;
}
}
a[i].v+=ans;
return ans;
}
int flow() {
int i;
a[s].v=MAXINT;
while (bfs()) {
for (i=0;i<=n;i++) a[i].cur=a[i].fe;
dfs(s,MAXINT);
}
return a[t].v;
}
};
NetWorkFlow c;

int main() {
int t,tt,n,m,i,sum;
scanf("%d",&t);
for (tt=1;tt<=t;tt++) {
scanf("%d%d",&n,&m);
c.clear(n+2,0,n+1);
sum=0;
for (i=0;i<m;i++) {
int u,v,d,b;
scanf("%d%d%d%d",&u,&v,&d,&b);
c.putedge(u,v,b);
c.putedge(0,v,d);
c.putedge(u,n+1,d);
sum+=d;
}
if (sum==c.flow()) printf("Case #%d: happy\n",tt);
else printf("Case #%d: unhappy\n",tt);
}
return 0;
}


解法2:最大权闭合子图。对于每个点,权值为只选该点的收益。对于每条边,新建一个点,权值为同时选中这条边上的两个点造成的收益和两个点的收益的和的差,然后向其两个端点连边。复杂度比上一个要高一些。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: