POJ 2125 Destroying the Graph 二分图最小点权覆盖

Destroying The Graph

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 8198   Accepted: 2635   Special Judge

Description

Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that Bob tries to destroy it. In a move he may take any vertex of the graph and remove either all arcs incoming into this vertex, or all arcs outgoing from this vertex. 
Alice assigns two costs to each vertex: Wi+ and Wi-. If Bob removes all arcs incoming into the i-th vertex he pays Wi+ dollars to Alice, and if he removes outgoing arcs he pays Wi- dollars. 
Find out what minimal sum Bob needs to remove all arcs from the graph.

Input

Input file describes the graph Alice has drawn. The first line of the input file contains N and M (1 <= N <= 100, 1 <= M <= 5000). The second line contains N integer numbers specifying Wi+. The third line defines Wi- in a similar way. All costs are positive and do not exceed 106 . Each of the following M lines contains two integers describing the corresponding arc of the graph. Graph may contain loops and parallel arcs.

Output

On the first line of the output file print W --- the minimal sum Bob must have to remove all arcs from the graph. On the second line print K --- the number of moves Bob needs to do it. After that print K lines that describe Bob‘s moves. Each line must first contain the number of the vertex and then ‘+‘ or ‘-‘ character, separated by one space. Character ‘+‘ means that Bob removes all arcs incoming into the specified vertex and ‘-‘ that Bob removes all arcs outgoing from the specified vertex.

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

Northeastern Europe 2003, Northern Subregion

【题意】:

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;
} 
时间: 2024-08-10 21:28:39

POJ 2125 Destroying the Graph 二分图最小点权覆盖的相关文章

POJ2125 Destroying The Graph 二分图 + 最小点权覆盖 + 最小割

思路来源:http://blog.csdn.net/lenleaves/article/details/7873441 求最小点权覆盖,同样求一个最小割,但是要求出割去了那些边, 只要用最终的剩余网络进行一次遍历就可以了,比较简单. 建图:同样是一个二分图,左边的点代表去掉出边, 右边的点代表去掉入边(小心别弄混),左边去掉出边的点与源点相连, 容量为wi- . 然后更据给出的弧进行连线,权值为INF 使用很好理解的EK算法:(360MS) //#pragma comment(linker, "

POJ 2125 --Destroying The Graph【最小割解决 &quot;最小点权覆盖问题&quot; &amp;&amp; 输出解(割边集) &amp;&amp; 各种不懂】

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7597   Accepted: 2434   Special Judge Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that B

二分图最小点权覆盖 二分图最大权独立集 方格取数 最小割

二分图最小点权覆盖: 每一条边 (u, v) 都是一个限制条件, 要求 u 和 v 不能同时取得. 我们考虑先取得所有的, 然后减去最小的点权. 建立原点 S , 连向二分图左边的所有点, 与 S 连通的意义是左边的点被选择了, 或者右边的点没有被选择. 建立汇点 T , 二分图右边的所有点连向它, 与 T 连通的意义是左边的点没有被选择, 或者右边的点被选择了. 利用最小割最大流定理, 我们跑最大流, 再根据最后一次 BFS 得出的情报构造方案. 定理 覆盖集与独立集互补. 证明 即证明覆盖集

POJ 3308 Paratroopers (二分图最小点权覆盖 -&gt; 最小割 -&gt; 最大流)

POJ 3308 Paratroopers 链接:http://poj.org/problem?id=3308 题意:有一个N*M的方阵,有L个伞兵降落在方阵上.现在要将所有的伞兵都消灭掉,可以在每行每列装一个高射炮,如果在某行(某列)装上高射炮之后,能够消灭所有落在该行(该列)的伞兵.每行每列安高射炮有费用,问如何安装能够使得费用之积最小. 思路:首先题目要求乘积最小,将乘积对e取对数,会发现就变成了求和.然后抽象出一个二分图,每一行是x部的一个点,每个点有权值,权值为费用取ln.每一列是y部

图论(网络流,二分图最小点权覆盖):POJ 2125 Destroying The Graph

Destroying The Graph Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that Bob tries to destroy it. In a move he may take any vertex of the graph and remove either all arcs in

poj 2125 Destroying The Graph 最小点权覆盖集+拆点+求割边

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7570   Accepted: 2423   Special Judge Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that B

【网络流】【最小点权覆盖】【NEERC 2003】【POJ2125】【cogs 1575】有向图破坏

1575. [NEERC 2003][POJ2125]有向图破坏 ★★★ 输入文件:destroyingthegraph.in 输出文件:destroyingthegraph.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] Alice和Bob正在玩如下的游戏.首先Alice画一个有N个顶点,M条边的有向图.然后Bob试着摧毁它.在一次操作中他可以找到图中的一个点,并且删除它所有的入边或所有的出边. Alice给每个点定义了两个值:Wi+和Wi-.如果Bob删除了第i个点

POJ2125 Destroying The Graph (最小点权覆盖集)(网络流最小割)

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8158   Accepted: 2620   Special Judge Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that B

poj 3686 The Windy&#39;s 二分图最小权和匹配KM

题意: 给n个玩具和m家工厂,每个玩具只能在一家工厂加工,给出每个玩具在每家工厂需要的加工时间,求这n个玩具完成时间平均值的最小值. 分析: 求最小和容易联系到二分图的最小权和匹配,这题的问题是n与m的大小关系是不确定的,也是就是说可能会有多个玩具到同一家工厂里加工的情况,这似乎与匹配的定义相矛盾.但仔细一想,如果多个玩具在同一工厂加工,他们的完成时间肯定是不一样的,所以讲w[i][j]=z 拆成w[i][0*m+j]=z,w[i][1*m+j]=2*z,w[i][2*m+j]=3*z.....