网上都是DLX搜索, 反正我是没学过DLX搜索, 直接二分匹配,代码比DLX搜索更短。
num[i] 表示i号开关控制的灯的数量
先用 数组Stol[i][j] 表示i号开关控制的第j(根据题目描述,j<=2)个灯。 Stol[i][j].v 是控制的灯的编号, Stol[i][j].sta 是此开关什么状态能打开对应的灯。
首先进行贪心:
1.如果i开关只控制一盏灯,那么此开关的状态必为 Stol[i][0].sta 用viss 标记开关,visl标记灯,表示已经确定
2.如果i开关控制两盏灯,并且Stol[i][0].sta == Stol[i][1].sta, 那么此开关状态必为Stol[i][0].sta, 用viss标记开关,visl标记灯,表示已经确定。
剩下的没用用viss标记的开关中,只有两种情况
1.控制0盏灯
2.控制两盏灯并且 Stol[i][0].sta != Stol[i][1].sta
对剩下未标记的灯和未标记的开关,进行二分匹配。
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
#include<ctime>
using namespace std;
void fre(){freopen("t.txt","r",stdin);}
#define ls o<<1
#define rs o<<1|1
#define MS(x,y) memset(x,y,sizeof(x))
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
const int INF = 1<<30;
const int M = 100000007 ;
const double eps = 1e-8;
const int MAXN = 200010;
struct STOL
{
int v,sta;
}Stol[505][2];
int n,m;
int num[505],match[505];//match和vis两个数组用于二分匹配,num[i]表示第i个开关控制灯的数量
bool visl[505],viss[505],ans[505],vis[505];
bool Find(int x)
{
int v;
for(int i = 0; i < 2; ++i)
{
v = Stol[x][i].v;
if(visl[v] || vis[v]) continue;
vis[v] = 1;
if(!match[v] || Find(match[v]))
{
match[v] = x;
ans[x] = Stol[x][i].sta;
return 1;
}
}
return 0;
}
int main()
{
//fre();
int tem,swch;
char ope[5];
while(~scanf("%d%d",&n,&m))
{
MS(num,0);MS(visl,0);MS(viss,0); MS(match,0);
int flag = 0;
for(int i = 1; i <= n; ++i)//输入
{
scanf("%d",&tem);
while(tem--)
{
scanf("%d%s",&swch,ope);
Stol[swch][num[swch]].v = i;
if(ope[1] == 'N') Stol[swch][num[swch]++].sta = 1;
else Stol[swch][num[swch]++].sta = 0;
}
}
for(int i = 1; i <= m; ++i)//贪心
{
if(num[i] == 1)
{
viss[i] = 1; ans[i] = Stol[i][0].sta;
if(visl[Stol[i][0].v]) continue;
flag++; visl[Stol[i][0].v] = 1;
}
else if(num[i] == 2)
{
if(Stol[i][0].sta == Stol[i][1].sta)
{
viss[i] = 1; ans[i] = Stol[i][0].sta;
if(!visl[Stol[i][0].v])
{
visl[Stol[i][0].v] = 1;
flag++;
}
if(!visl[Stol[i][1].v])
{
visl[Stol[i][1].v] = 1;
flag++;
}
}
}
}
for(int i = 1; i <= m; ++i)//二分匹配
{
if(viss[i]) continue;
MS(vis,0);
if(num[i] == 2 && Find(i)) flag++;
}
if(flag == n)//输出
{
if(ans[1]) printf("ON");
else printf("OFF");
for(int i = 2; i <= m; ++i)
if(ans[i]) printf(" ON");
else printf(" OFF");
puts("");
}
else printf("-1\n");
}
}