zoukankan      html  css  js  c++  java
  • codeforces gym 100357 I (费用流)

    题目大意

     

      给出一个或与表达式,每个正变量和反变量最多出现一次,询问是否存在一种方案使得每个或式中有且仅有一个变量的值为1。

    解题分析

      将每个变量拆成三个点x,y,z。 y表示对应的正变量,z表示对应的反变量。

      由S向每个点的x部连一条流量为1的边,表示该变量的某个正变量或反变量的取值为1。

      由每个点的x部向y部和z部分别连一条流量为1的边,表示每个正变量和反变量仅有一个取值为1。

      若某个或式中含有某个变量,则由该变量的y部或z部向或式连一条流量为1的边。表示该变量可以使该或式的结果为1。

      由每个或式向T连一条流量为1的边,表示该或式被满足,且仅有一个变量的取值为1。

      仅仅这么连还是不够的,因为如果某个变量的正变量和反变量同时出现,那么正变量或反变量中必定有一个值为1,对应到图上则是S向该变量的x部必须有1的流量。

      所以可以向这条边添加上-1的费用,使得该变量的值优先被满足。

      跑一遍最小费用最大流,如果是满流且费用的绝对值等于必须被确定值的变量的数量,则说明可以成功满足。

      输出方案时只需遍历一下残余网络中的边,如果残余网络中没有流量则说明该变量被选择了,最后注意一下细节,确定一下对于每个变量选1还是选0。

    参考程序

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define rep(i,x,y) for (int i=x;i<=y;i++)
      5 const int N=1000;
      6 const int INF=2000000000;
      7 
      8 int n,m,S,T,sum,minC,maxF;
      9 int lt[N*4],flag[N],dis[N*4],pd[N*4],pre[N*4],sgn[N*4];
     10 vector <int> vec[N];
     11 
     12 struct edge{
     13     int u,v,f,w,nt;
     14 }eg[N*6];
     15 
     16 void add(int u,int v,int f,int w)
     17 {
     18     //cout<<u<<" "<<v<<" "<<f<<" "<<w<<endl; 
     19     eg[++sum]=(edge){u,v,f,w,lt[u]}; lt[u]=sum;    
     20     eg[++sum]=(edge){v,u,0,-w,lt[v]}; lt[v]=sum;
     21 }
     22 
     23 bool spfa()
     24 {
     25     queue <int> Q;
     26     rep (i,S,T) dis[i]=INF,pd[i]=0,pre[i]=-1;
     27     dis[S]=0; pd[S]=1; Q.push(S);
     28     while (!Q.empty())
     29     {
     30         int u=Q.front();
     31         for (int i=lt[u];i;i=eg[i].nt)
     32         {
     33             int v=eg[i].v;
     34             if (eg[i].f>0)
     35             {
     36                 if (dis[u]+eg[i].w<dis[v])
     37                 {
     38                     dis[v]=dis[u]+eg[i].w;
     39                     pre[v]=i;
     40                     if (!pd[v])
     41                     {
     42                         Q.push(v);
     43                         pd[v]=1;
     44                     }
     45                 }
     46             }
     47         }
     48         pd[u]=0; Q.pop();
     49     }
     50     return dis[T]!=INF;
     51 }
     52 void minCmaxF()
     53 {
     54     int flow;
     55     while (spfa())
     56     {
     57         flow=INF;
     58         for (int i=pre[T];~i;i=pre[eg[i].u])
     59             flow=min(flow,eg[i].f);
     60         for (int i=pre[T];~i;i=pre[eg[i].u])
     61             eg[i].f-=flow,eg[i^1].f+=flow;
     62         maxF+=flow;
     63         minC+=flow*dis[T];
     64     }
     65 }
     66 
     67 int main()
     68 {
     69     freopen("sat.in","r",stdin);
     70     freopen("sat.out","w",stdout);
     71     
     72     cin.sync_with_stdio(0);
     73     sum=1; memset(lt,0,sizeof(lt));
     74     int limit=0;
     75 
     76     cin>>n>>m;
     77     S=0; T=3*n+m+1;
     78     rep(i,1,m) 
     79     {
     80         int num; cin>>num;
     81         rep(j,1,num)
     82         {
     83             int x; cin>>x;
     84             flag[abs(x)]++;
     85             if (x>0) sgn[x]=1; else sgn[x]=-1;
     86             vec[i].push_back(x);
     87         }
     88     }
     89     rep(i,1,n) if (flag[i]==2) add(S,i,1,-1),limit++; else add(S,i,1,0);
     90     rep(i,1,n) {add(i,n+2*i-1,1,0); add(i,n+2*i,1,0);}
     91     rep(i,1,m)
     92     {
     93         for (auto v:vec[i]) 
     94         {
     95             int x=v>0?n+2*abs(v)-1:n+2*abs(v);
     96             add(x,n*3+i,1,0);
     97         }
     98         add(3*n+i,T,1,0);
     99     }
    100     minC=maxF=0;
    101     minCmaxF();
    102     vector <int> ans;
    103     if (minC==-limit && maxF==m)
    104     {
    105         cout<<"YES"<<endl;
    106         for (int i=lt[S];i;i=eg[i].nt)
    107         {
    108             if (eg[i].f==1) 
    109             {
    110                 if (sgn[eg[i].v]==1) ans.push_back(0); else ans.push_back(1);
    111             }
    112             else
    113             {
    114                 if (eg[lt[eg[i].v]].f==0) ans.push_back(0); else ans.push_back(1);
    115             }
    116         }
    117         for (int i=ans.size()-1;i>=0;i--) cout<<ans[i]<<" ";
    118         cout<<endl;
    119     }
    120     else cout<<"NO"<<endl;
    121 }
    View Code

  • 相关阅读:
    交叉编译
    CompactPCI之系统管理设计与应用
    羽毛球发球规则
    记忆里第一次看孙淳演的电视剧——《浦江叙事》
    理财工具——七大标准比率
    samba常见问题
    Samba配置文件常用参数详解
    samba安装和简单配置
    mdadm中文man帮助
    说一说羽毛球的几种概念
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/6790809.html
Copyright © 2011-2022 走看看