2017寒假集训 2-C
HDU 2828 Lamp
网络流
传送门:HustOJ
传送门:HDU
题意
N个灯,M个开关。每个开关最多控制两盏灯。
输入N个灯,每个灯受k个开关控制,第i(
0<i<=k
)个开关为开或关时这个灯可以亮。输出使灯全亮的开关方案,无解-1。
Lamp 1, the list is “1 ON 3 OFF 9 ON”, that means Lamp 1 will be lighted if the Switch 1 is at the “ON” state OR the Switch 3 is “OFF” OR the Switch 9 is “ON”.
注意如果一个灯受多个开关控制,那么其中任意一个开关状态符合时这个灯就能亮。
思路
网上说DLX搜索可以做,但我不会DLX。所以网络流做的。
如果一个开关控制两个灯,且两个灯状态要求相同,那么添加边:源点到开关容量2,
如果两个灯状态不同或只控制一个灯,那么容量是1,表示一种互斥状态。
添加开关到它控制的灯的边,容量1;以及灯到汇,容量1。
网络流,如果流小于灯数,那么无解。
然后对于一个开关,如果他控制两个状态要求相同的灯或一盏灯,那么他的状态确定;如果他控制的两个灯要求不一样,那么进到网络流里面,看看从这开关出发的边流向哪个灯了,他的状态就是哪个灯要求的状态。
注意如果这个开关出发没有流,说明他没用,他对灯造不成影响。随便输出就好。
我的代码特别长,估计对状态的处理不太好吧。不过思路大概就是这样。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#define _ ios_base::sync_with_stdio(0);cin.tie(0);
using namespace std;
const int MAXN=1007;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
struct Dinic
{
struct Edge
{
int from, to, cap, flow; //cap容量 flow流量
Edge() {}
Edge(int u, int v, int c, int f)
{
from=u;
to=v;
cap=c;
flow=f;
}
} e[MAXN];
vector<Edge> edges; //顺序的插入边
vector<int> G[MAXN]; //保存边号
bool vis[MAXN]; //BFS使用
int d[MAXN];
int cur[MAXN];
void init(int n)
{
for(int i=0; i < n; i++)
G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0)); //单向边第三个参数写0,双向边写cap
int t_m=edges.size();
G[from].push_back(t_m-2);
G[to].push_back(t_m-1);
}
bool BFS(int s, int t)
{
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
d[s]=0;
vis[s]=1;
while(!Q.empty())
{
int x=Q.front();
Q.pop();
for(int i=0; i < G[x].size(); i++)
{
Edge &e=edges[G[x][i]];
if(!vis[e.to]&&e.cap > e.flow) //残量网络
{
vis[e.to]=1;
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a, int s, int t)
{
if(x==t||a==0)
return a;
int flow=0, _f;
for(int &i=cur[x]; i < G[x].size(); i++)
{
Edge &e=edges[G[x][i]];
if(d[x]+1==d[e.to]&&(_f=DFS(e.to, min(a, e.cap-e.flow), s, t)) > 0)
{
e.flow+=_f;
edges[G[x][i]^1].flow-=_f;
flow+=_f;
a-=_f;
if(a==0)
break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
int flow=0;
while(BFS(s, t))
{
memset(cur, 0, sizeof(cur));
flow+=DFS(s, oo, s, t);
}
return flow;
}
} dinic;
int sw[MAXN][5]; //1表示有一个要求on的 -1表示一个要求off的 2 -2表示两个 0表示1on1off
int main()
{
_ int n, m;
while(cin>>n)
{
cin>>m;
dinic.init(1007);
memset(sw, 0, sizeof(sw));
for(int i=1; i<=n; i++)
{
int tn;
cin>>tn;
while(tn--)
{
int t;
string s;
cin>>t>>s;
if(sw[t][0]==0)
sw[t][1]=(s[1]=='N' ? 1 : -1), sw[t][2]=i;
else if(sw[t][0]==1||sw[t][0]==-1)
sw[t][3]=(s[1]=='N' ? 1 : -1), sw[t][4]=i;
sw[t][0]+=(s[1]=='N' ? 1 : -1);
}
}
const int sup_s=1001, sup_t=1002;
for(int i=1; i<=m; i++)
{
if(sw[i][0]==0||sw[i][0]==1||sw[i][0]==-1)
dinic.AddEdge(sup_s, i, 1);
else
dinic.AddEdge(sup_s, i, 2);
if(sw[i][0]==0||sw[i][0]==2||sw[i][0]==-2)
dinic.AddEdge(i, m+sw[i][2], 1), dinic.AddEdge(i, m+sw[i][4], 1);
else
dinic.AddEdge(i, m+sw[i][2], 1);
}
for(int i=1; i<=n; i++)
{
dinic.AddEdge(m+i, sup_t, 1);
}
int ma=dinic.Maxflow(sup_s, sup_t);
if(ma < n)
cout<<-1<<endl;
else
{
for(int i=1; i<=m; i++)
{
if(sw[i][0]==2||sw[i][0]==1)
cout<<"ON"<<(i==m ? '\n' : ' ');
else if(sw[i][0]==-2||sw[i][0]==-1)
cout<<"OFF"<<(i==m ? '\n' : ' ');
else
{
bool ff=0;
for(int kkk=0;kkk<dinic.G[i].size();kkk++)
{
int u=dinic.G[i][kkk];
if(dinic.edges[u].flow > 0)
{
ff=1;
if(dinic.edges[u].to==sw[i][2]+m)
{
cout<<(sw[i][1]==1 ? "ON" : "OFF")<<(i==m ? '\n' : ' ');
break;
}
else if(dinic.edges[u].to==sw[i][4]+m)
{
cout<<(sw[i][3]==1 ? "ON" : "OFF")<<(i==m ? '\n' : ' ');
break;
}
}
}
if(!ff)//这个开关没有流,那么开关与否无所谓
{
cout<<"ON"<<(i==m ? '\n' : ' ');
}
}
}
}
}
//system("pause");
return 0;
}