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。
参考程序
#include <bits/stdc++.h>
using namespace std; #define rep(i,x,y) for (int i=x;i<=y;i++)
const int N=;
const int INF=; int n,m,S,T,sum,minC,maxF;
int lt[N*],flag[N],dis[N*],pd[N*],pre[N*],sgn[N*];
vector <int> vec[N]; struct edge{
int u,v,f,w,nt;
}eg[N*]; void add(int u,int v,int f,int w)
{
//cout<<u<<" "<<v<<" "<<f<<" "<<w<<endl;
eg[++sum]=(edge){u,v,f,w,lt[u]}; lt[u]=sum;
eg[++sum]=(edge){v,u,,-w,lt[v]}; lt[v]=sum;
} bool spfa()
{
queue <int> Q;
rep (i,S,T) dis[i]=INF,pd[i]=,pre[i]=-;
dis[S]=; pd[S]=; Q.push(S);
while (!Q.empty())
{
int u=Q.front();
for (int i=lt[u];i;i=eg[i].nt)
{
int v=eg[i].v;
if (eg[i].f>)
{
if (dis[u]+eg[i].w<dis[v])
{
dis[v]=dis[u]+eg[i].w;
pre[v]=i;
if (!pd[v])
{
Q.push(v);
pd[v]=;
}
}
}
}
pd[u]=; Q.pop();
}
return dis[T]!=INF;
}
void minCmaxF()
{
int flow;
while (spfa())
{
flow=INF;
for (int i=pre[T];~i;i=pre[eg[i].u])
flow=min(flow,eg[i].f);
for (int i=pre[T];~i;i=pre[eg[i].u])
eg[i].f-=flow,eg[i^].f+=flow;
maxF+=flow;
minC+=flow*dis[T];
}
} int main()
{
freopen("sat.in","r",stdin);
freopen("sat.out","w",stdout); cin.sync_with_stdio();
sum=; memset(lt,,sizeof(lt));
int limit=; cin>>n>>m;
S=; T=*n+m+;
rep(i,,m)
{
int num; cin>>num;
rep(j,,num)
{
int x; cin>>x;
flag[abs(x)]++;
if (x>) sgn[x]=; else sgn[x]=-;
vec[i].push_back(x);
}
}
rep(i,,n) if (flag[i]==) add(S,i,,-),limit++; else add(S,i,,);
rep(i,,n) {add(i,n+*i-,,); add(i,n+*i,,);}
rep(i,,m)
{
for (auto v:vec[i])
{
int x=v>?n+*abs(v)-:n+*abs(v);
add(x,n*+i,,);
}
add(*n+i,T,,);
}
minC=maxF=;
minCmaxF();
vector <int> ans;
if (minC==-limit && maxF==m)
{
cout<<"YES"<<endl;
for (int i=lt[S];i;i=eg[i].nt)
{
if (eg[i].f==)
{
if (sgn[eg[i].v]==) ans.push_back(); else ans.push_back();
}
else
{
if (eg[lt[eg[i].v]].f==) ans.push_back(); else ans.push_back();
}
}
for (int i=ans.size()-;i>=;i--) cout<<ans[i]<<" ";
cout<<endl;
}
else cout<<"NO"<<endl;
}
codeforces gym 100357 I (费用流)的更多相关文章
- CodeForces 164C Machine Programming 费用流
Machine Programming 题目连接: http://codeforces.com/problemset/problem/164/B Descriptionww.co One remark ...
- Codeforces 708D 上下界费用流
给你一个网络流的图 图中可能会有流量不平衡和流量>容量的情况存在 每调整一单位的流量/容量 需要一个单位的花费 问最少需要多少花费使得原图调整为正确(可行)的网络流 设当前边信息为(u,v,f, ...
- CodeForces 1187G Gang Up 费用流
题解: 先按时间轴将一个点拆成100个点. 第一个点相当于第一秒, 第二个点相当于第二秒. 在这些点之间连边, 每1流量的费用为c. 再将图上的边也拆开. 将 u_i 向 v_i+1 建边. 将 v_ ...
- codeforces gym 100357 J (网络流)
题目大意 有n种物品,m种建筑,p个人. n,m,p∈[1,20] 每种建筑需要若干个若干种物品来建造.每个人打算建造一种建筑,拥有一些物品. 主角需要通过交易来建造自己的建筑,交易的前提是对方用多余 ...
- codeforces gym 100357 H (DP 高精度)
题目大意 有r*s张扑克牌,数字从1到 r,每种数字有s种颜色. 询问对于所有随机的d张牌,能选出c张组成顺子的概率和组成同花的概率. 解题分析 对于组成顺子的概率,令dp[i][j][k]表示一共选 ...
- codeforces gym 100357 K (表达式 模拟)
题目大意 将一个含有+,-,^,()的表达式按照运算顺序转换成树状的形式. 解题分析 用递归的方式来处理表达式,首先直接去掉两边的括号(如果不止一对全部去光),然后找出不在括号内且优先级最低的符号.如 ...
- Gym - 101492I 区间限制费用流
https://cn.vjudge.net/problem/Gym-101492I 如果用单个点代表每个区间 利用拆点来限制区间的流量的话 点是 n^2/2+m个 边是2*n^2条 但是这样会T 解法 ...
- Codeforces Gym 100002 E "Evacuation Plan" 费用流
"Evacuation Plan" Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10 ...
- Codeforces Gym 101190M Mole Tunnels - 费用流
题目传送门 传送门 题目大意 $m$只鼹鼠有$n$个巢穴,$n - 1$条长度为$1$的通道将它们连通且第$i(i > 1)$个巢穴与第$\left\lfloor \frac{i}{2}\rig ...
随机推荐
- c++ memset函数
函数名称:memset 函数所需头文件:#include<cstring> 函数作用:内存赋值函数,用来给某一块内存空间进行赋值的. 函数结构:memset(变量,一个数字,一个数字) ...
- BFS POJ 2251 Dungeon Master
题目传送门 /* BFS:这题很有意思,像是地下城,图是立体的,可以从上张图到下一张图的对应位置,那么也就是三维搜索,多了z坐标轴 */ #include <cstdio> #includ ...
- ACM_天涯若比邻(最小与最大相邻素数)
天涯若比邻 Time Limit: 2000/1000ms (Java/Others) Problem Description: 一心想搞ACM的小G最近迷上了数论,特别对于跟“素数”相关的问题特别有 ...
- EditText(7)EditText输入事件监听
EditText.addTextChangedListener(TextWatcher watcher); void initSearch(){ search = (EditText) findVie ...
- ora-20000 unable to analyze
ora-20000 unable to analyze 无法分析表 check: select * from wmsprdata.cmp3$88278表不存在. result:应该是系统自动任务2:0 ...
- C#基础 集合
//数组定义的时候 //需要定义数据类型 //需要定义初始长度 //int [] array = new int[5]; //int a = array.Length; //集合 //ArrayLis ...
- Java 8 (1) 行为参数化
行为参数化就是可以帮助你处理频繁变更需求的一种软件开发模式.它意味着拿出一个代码块,把它准备好却不去执行它.这个代码块以后可以被你程序的其他部分调用,这意味着你可以推迟这块代码的执行.例如:你可以将代 ...
- Modbus消息帧
两种传输模式中(ASCII和RTU),传输设备以将Modbus消息转为有起点和终点的帧,这就允许接收的设备在消息起始处开始工作,读地址分配信息,判断哪一个设备被选中(广播方式则传给所以设备),判知何时 ...
- Linux shell脚本中 数组的声明:
数组的声明: 1)array[key]=value # array[0]=one,array[1]=two 复制代码 2)declare -a array # array被当作数组名 复制代码 3)a ...
- servlet——web应用中路径问题
target.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html ...