• POJ 2125 最小点权覆盖集(输出方案)


    题意:给一个图(有自回路,重边),要去掉所有边,规则:对某个点,可以有2种操作:去掉进入该点
    的所有边,也可以去掉出该点所有边,(第一种代价为w+,第二种代价为w-)。求最小代价去除所有边。


    己思:点的权被分为出入?必然拆点啊!每个点一分为二,点权:出的为出点权,入的为入点权,原来边仍在
    ,注意,这里(1-)->(1+),不多添加边,因为相当于求新图的最小点权覆盖集(覆盖所有边,每选一个点
    恰好去除了它的边(要原图的入边或出边),),所以不可以在新图上再添加边(这里不是到不到的问题了)
    ,若添加边i-->i+,最小割可能发生变化。所以求二分图最小割问题,=新添s,t的最大流。
    这题要输出方案,即最小点权覆盖集的点,即最小割(该二分图为简单割),遍历边,若该边俩头

    vis[]值(dinic后)不同,(i%2==0)必然为最小割边。

    ps:神题??

    #include<iostream>  //110ms ,1A
    #include<queue>
    #include<cstdio>
    #include<vector>
    using namespace std;
    int n,m; int e[30000][3];int head[208];int nume=0;
    const int inf=0x3f3f3f3f;
    void addedge(int f,int l,int w)
    {
        e[nume][0]=l;e[nume][1]=head[f];head[f]=nume;
        e[nume++][2]=w;
        e[nume][0]=f;e[nume][1]=head[l];head[l]=nume;
        e[nume++][2]=0;
    }
    int vis[205];int level[205];
    bool bfs()
    {
        for(int i=0;i<=2*n+1;i++)
            vis[i]=level[i]=0;
    
        vis[0]=1;queue<int>q;q.push(0);
        while(!q.empty())
        {
            int cur=q.front();q.pop();
            for(int i=head[cur];i!=-1;i=e[i][1])
            {     int v=e[i][0];
                if(!vis[v]&&e[i][2]>0)
                  {
                      level[v]=level[cur]+1;
                      if(v==n*2+1)return 1;
                      vis[v]=1;
                      q.push(v);
                  }
            }
        }
        return vis[n*2+1];
    }
    int dfs(int u,int minf)
    {
        if(minf==0||u==n*2+1)return minf;
        int sumf=0,f;
        for(int i=head[u];i!=-1&&minf;i=e[i][1])
        {    int v=e[i][0];
            if(level[v]==level[u]+1&&e[i][2]>0)
            {
                f=dfs(v,minf<e[i][2]?minf:e[i][2]);
                e[i][2]-=f;e[i^1][2]+=f;
                sumf+=f;minf-=f;
            }
        }
        return sumf;
    }
    int dinic()
    {
        int sum=0;
        while(bfs())
        sum+=dfs(0,inf);
        return sum;
    }
    int main()
    {
        scanf("%d%d",&n,&m);         //建图
        int temp,ff,ll;    nume=0;
        for(int i=0;i<n*2+1;i++)
            head[i]=-1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&temp);
            addedge(i+n,n*2+1,temp);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&temp);
            addedge(0,i,temp);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&ff,&ll);
            addedge(ff,ll+n,inf);
        }
        int ans=dinic();
        printf("%d
    ",ans);
        int count=0;
        vector<int>cut1,cut2;       //  找方案,
        for(int i=0;i<=2*n+1;i++)
           for(int j=head[i];j!=-1;j=e[j][1])
           {
               if(j%2==0&&e[j][2]==0&&vis[i]==1&&vis[e[j][0]]==0)  //最小割边
                  {
                      count++;
                        if(i==0)
                       cut1.push_back(e[j][0]);
                       else if(e[j][0]==2*n+1)
                         cut2.push_back(i-n);
                  }
           }
           printf("%d
    ",count);
           for(int i=0;i<cut1.size();i++)
             printf("%d -
    ",cut1[i]);
           for(int i=0;i<cut2.size();i++)
             printf("%d +
    ",cut2[i]);
        return 0;
    }
    


  • 相关阅读:
    xargs命令
    grep命令详细解析 --非原创 原作者ggjucheng
    centos如何安装Python3
    Custom Draw 基础(转载)
    Make 命令教程(转载)
    选择Blobs (Evision)
    图像预处理(Evision)
    一个野生程序员开博日
    Ubuntu 14.04 apt源更新
    python核心编程3-13
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925797.html
Copyright © 2020-2023  润新知