1575. [NEERC 2003][POJ2125]有向图破坏
★★★ 输入文件:destroyingthegraph.in 输出文件:destroyingthegraph.out 简单对比
时间限制:1 s 内存限制:256 MB
【题目描述】
Alice和Bob正在玩如下的游戏。首先Alice画一个有N个顶点,M条边的有向图。然后Bob试着摧毁它。在一次操作中他可以找到图中的一个点,并且删除它所有的入边或所有的出边。
Alice给每个点定义了两个值:Wi+和Wi-。如果Bob删除了第i个点所有的入边他要给Alice付Wi+元,如果他删除了所有的出边就需要给Alice付Wi元。
找到Bob删除图中所有边需要的最小花费。
【输入格式】
输入数据描述了Alice画下的图。
输入文件的第一行有两个数N,M(1<=N<=100,1<=M<=5000)。第二行有N个整数,描述了N个点的Wi+,同样的第三行是这N个点的Wi-。所有的费用都是正数并且不超过10^6。接下来的M行每行有两个数,代表有向图中相应的一条边。
【输出格式】
输出一行一个整数,即Bob的最小花费。
【样例输入】
3 6
1 2 3
4 2 1
1 2
1 1
3 2
1 2
3 1
2 3
【样例输出】
5
【提示】
样例的一个方案是:删除点1,2所有的入边,删除点2所有的出边。
输出格式和原题有所不同。原题要求输出方案。
【来源】
Northeastern Europe 2003,Northern Subregion (NEERC 2003)
POJ 2125 Destroying the Graph
题解:
通过题目可以发现,我们要求的就是在使用最小的点权的情况下选中所有边,每条边都可以被他的两个端点选中,且出入点权可能不同,于是就可以发现这是一个最小点权覆盖。
建边:
1>先建立虚拟源S和汇T,把每个点拆成两个,ia,ib。
2>从S向ia连一条流量为wi-的边,从ib向T连一条流量为wi+的边。
3>原图中的边从ua向vb连一条流量无穷大的边。
然后跑最大流即可。
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 110
#define M 5100
#define inf 0x3fffffff
using namespace std;
struct Edge{
int v,next,cap;
}edge[10*M];
int n,m,num=-1,S,T,ans;
int w1[N],w2[N],head[2*N],pre[2*N],gap[2*N],dis[2*N],cur[2*N];
int in(){
int x=0; char ch=getchar();
while (ch<‘0‘ || ch>‘9‘) ch=getchar();
while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
return x;
}
void add(int u,int v,int cap){
edge[++num].v=v; edge[num].cap=cap;
edge[num].next=head[u]; head[u]=num;
}
void build(){
S=0,T=n<<1|1;
for (int i=1; i<=n; i++)
w1[i]=in(),add(i+n,T,w1[i]),add(T,i+n,0);
for (int i=1; i<=n; i++)
w2[i]=in(),add(S,i,w2[i]),add(i,S,0);
for (int i=1; i<=m; i++){
int u=in(),v=in();
add(u,v+n,inf),add(v+n,u,0);
}
}
void isap(){
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
for (int i=0; i<=T; i++) cur[i]=head[i];
int u=S,maxn=0,k=inf,v;
gap[0]=T+1; pre[S]=S;
while (dis[S]<=T){
bool f=0;
while (!f){
f=1;
for (int i=cur[u]; i!=-1; i=edge[i].next){
v=edge[i].v;
if (edge[i].cap>0 && dis[u]==dis[v]+1){
k=min(k,edge[i].cap);
pre[v]=u; cur[u]=i; u=v;
if (u==T){
for (u=pre[u]; v!=S; v=u,u=pre[u]){
edge[cur[u]].cap-=k;
edge[cur[u]^1].cap+=k;
}
maxn+=k; k=inf;
}
f=0; break;
}
}
}
int minn=T+1;
for (int i=head[u]; i!=-1; i=edge[i].next){
v=edge[i].v;
if (edge[i].cap>0 && dis[v]<minn)
cur[u]=i,minn=dis[v];
}
gap[dis[u]]--;
if (!gap[dis[u]]) break;
dis[u]=minn+1; gap[dis[u]]++; u=pre[u];
}
ans=maxn;
}
int main(){
memset(head,-1,sizeof(head));
n=in(); m=in();
build(); isap();
printf("%d\n",ans);
return 0;
}
时间: 2024-12-16 23:03:13