hdu3251 最小割

来源:互联网 发布:打字淘宝兼职是真的吗 编辑:程序博客网 时间:2024/05/16 08:41

http://acm.hdu.edu.cn/showproblem.php?pid=3251
题意:
给定一张图,可以选择一些点,每个点有对应的点权,每条边有边权,选择一部分点后,必须摧毁一部分边,保证 1 不能到达这些点,获得的收益就是选择的点权和减去摧毁的边权和。并求出摧毁哪些边。
做法:
将带权的点连接一条边到t点,容量为该点的点权。最后将s连到1,容量为inf。求最小割,利用总的点权和减去最小割就是获得的收益。因为如果这个点不选择的话,最小割肯定包含该点到t点的边。如果要选择的话,肯定不包含,必须包含之前的点。
求摧毁的边,就可以跑完最大流以后,用dfs求一遍,将图划分成两个集合,如果一条边的起点与s在同一个集合,终点与t在同一个集合那么这条就是割边,(并且要排除掉与t相连的那些割边)。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <set>#include <stack>#include <vector>using namespace std;const int M_node = 4000,M_edge = 210009,INF = 0x3f3f3f3f;struct edge{    int to,cap,next;    int index;}edge[M_edge];int head[M_node],iter[M_node];int level[M_node];bool vis[M_node];int num;int n,m,f,s,t;int sum;void init(){    memset(head,-1,sizeof(head));    memset(vis,false,sizeof(vis));    num = 0;    sum = 0;}void add_edge(int u,int v,int cap,int index){    edge[num].to = v; edge[num].cap = cap ; edge[num].next = head[u] ; edge[num].index = index ; head[u] = num++;    edge[num].to = u; edge[num].cap = 0 ; edge[num].next = head[v] ; edge[num].index = -1 ; head[v] = num++;}bool bfs(int s,int t){    memset(level,-1,sizeof(level));    level[s] = 0;    queue<int> q;    q.push(s);    while(!q.empty())    {        int v = q.front();        q.pop();        for(int i = head[v];i != -1;i = edge[i].next)        {            int u = edge[i].to;            if(level[u] < 0 && edge[i].cap)            {                level[u] = level[v] + 1;                q.push(u);            }        }    }    return level[t] != -1;}int dfs(int v,int t,int f){    if(v == t) return f;    for(int &i = iter[v];i != -1;i = edge[i].next)    {        int u = edge[i].to;        if(level[u] > level[v] && edge[i].cap > 0)        {            int d = dfs(u,t,min(f,edge[i].cap));            if(d > 0)            {                edge[i].cap -= d;                edge[i^1].cap += d;                return d;            }        }    }    level[v] = -1;    return 0;}int max_flow(int s,int t){    int flow = 0;    while(bfs(s,t))    {        for(int i = 0;i <= t+10;i++) iter[i] = head[i];        int f = 0;        while((f = dfs(s,t,INF)) > 0) flow += f;    }    return flow;}void dfs(int u,int fa){    for(int i = head[u];i != -1;i = edge[i].next)    {        int v = edge[i].to;        if(!vis[v] && edge[i].cap > 0)        {            vis[v] = true;            dfs(v,u);        }    }}int main(){    int T;    scanf("%d",&T);    int kas = 1;    while(T--)    {        scanf("%d%d%d",&n,&m,&f);        init();        s = 0;        t = n+1;        add_edge(s,1,INF,-1);        for(int i = 0;i < m;i++)        {            int u,v,cap;            scanf("%d%d%d",&u,&v,&cap);            add_edge(u,v,cap,i+1);        }        for(int i = 0;i < f;i++)        {            int u,cost;            scanf("%d%d",&u,&cost);            add_edge(u,t,cost,-1);            sum += cost;        }        int ans = max_flow(s,t);        ans = sum - ans;        printf("Case %d: %d\n",kas++,ans);        vis[1] = true;        dfs(1,-1);        queue<int> q;        for(int i = 0;i < num;i += 2) // += 2 保证是正向边        {            if(vis[edge[i^1].to] && !vis[edge[i].to] && edge[i].index != -1) q.push(edge[i].index);        }        printf("%d",q.size());        while(!q.empty())        {            printf(" %d",q.front());            q.pop();        }        printf("\n");        /*set<int> s;        for(int i = 1;i <= n;i++)        {            for(int j = head[i]; j != -1 ;j = edge[j].next)            {                int v = edge[j].to;                if(vis[i] && !vis[v] && edge[j].index != -1) s.insert(edge[j].index); //必须保证是正向边            }        }        printf("%d",s.size());        set<int>::iterator it;        for(it = s.begin();it != s.end();it++)        {            printf(" %d",*it);        }        printf("\n");*/    }    return 0;}
0 0