您的位置:首页 > 其它

poj2125 最小点权覆盖集

2015-10-30 21:01 190 查看
题意:有一张图,对于每个点,有出边和入边,现在目的是删除改图的所有边,对于每个点,删除出边的花费Wi-,删除入边的花费Wi+,现在的目的求删去所有边后的花费最小。

建图方法:对于每个点i,拆点为i,i+n,对于入边,从i+n想汇点T连边,值为入边花费;对于出边,从S向i连边,权值为出边花费。m组相连的边(x,y),从x向y+n连边, 费用INF。求出最小割。

然后是计算删除的是哪些点。对于完成最小割后的图,从源点S进行dfs,如果能够访问到,标记。对于不能访问到的点,i<=n时,这个点的出边是属于割集的,即所求点,且为‘-’;如果i>n,表示该点为需要删除的边的点,为'+';

最小割后的图片


(ps:S,T写错了。。。)

根据图很明显的可以看出哪些边时需要删除,并且是哪些点的边。

#include<stdio.h>
#include<string.h>
#include<queue>
#define INF 99999999
using namespace std;
const int maxn = 120*2;
const int maxm = 5010;
struct node
{
int to;
int v;
int flag;
int next;
}edge[(maxn+maxm)*2];
struct ans_point
{
int x;
int flag;
}ans_p[maxn];
int index,pre[maxn],vis[maxn],S,T;
int in[maxn],out[maxn];
void add(int x,int y,int z)
{
edge[index].to=y;
edge[index].v=z;
edge[index].flag=index+1;
edge[index].next=pre[x];
pre[x]=index++;
edge[index].to=x;
edge[index].v=0;
edge[index].flag=index-1;
edge[index].next=pre[y];
pre[y]=index++;
}
int dfs(int u,int low)
{
int i,used=0;
if(u==T)
return low;
for(i=pre[u];i!=-1&&used<low;i=edge[i].next)
{
if(edge[i].v&&vis[edge[i].to]==vis[u]+1)
{
int a=dfs(edge[i].to,min(low-used,edge[i].v));
edge[i].v-=a;
edge[edge[i].flag].v+=a;
used+=a;
}
}
if(!used)
vis[u]=-1;
return used;
}
bool BFS()
{
int i;
queue<int>q;
memset(vis,-1,sizeof(vis));
vis[0]=1;
q.push(0);
while(!q.empty())
{
int t=q.front();
q.pop();
for(i=pre[t];i!=-1;i=edge[i].next)
{
if(edge[i].v&&vis[edge[i].to]<0)
{
vis[edge[i].to]=vis[t]+1;
q.push(edge[i].to);
}
}
}
if(vis[T]>0)
return true;
return false;
}
void cnt_dfs(int u)
{
int i;
vis[u]=1;
for(i=pre[u];i!=-1;i=edge[i].next)
{
if(edge[i].v>0&&!vis[edge[i].to])
cnt_dfs(edge[i].to);
}
}
int main()
{
int n,m,i,j;
while(~scanf("%d%d",&n,&m))
{
index=1;
memset(pre,-1,sizeof(pre));
S=0,T=2*n+1;
for(i=1;i<=n;i++)
{
scanf("%d",&in[i]);
add(i+n,T,in[i]);
}
for(i=1;i<=n;i++)
{
scanf("%d",&out[i]);
add(S,i,out[i]);
}
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y+n,INF);
}
int ans=0;
while(BFS())
{
int a=dfs(0,INF);
if(!a)break;
ans+=a;
}
printf("%d\n",ans);
memset(vis,0,sizeof(vis));
cnt_dfs(0);
int cnt=0;
for(i=1;i<=n*2;i++)
{
if(i>n)
{
if(vis[i])
{
ans_p[cnt].x=i;
ans_p[cnt++].flag=1;
}
}
else
{
if(!vis[i])
{
ans_p[cnt].x=i;
ans_p[cnt++].flag=0;
}
}
}
printf("%d\n",cnt);
for(i=0;i<cnt;i++)
{
if(ans_p[i].x>n)
printf("%d ",ans_p[i].x-n);
else printf("%d ",ans_p[i].x);
if(ans_p[i].flag==0)
printf("-\n");
else printf("+\n");
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: