题目大意:
A A A和 B B B做石头剪刀布游戏,已知 A A A的所有选择,和 m m m个对 B B B选择的限制,问是否存在 B B B胜出的可能。
思路:
B
B
B要获胜,每轮
B
B
B都要选择平局和获胜的选择,问题转化为
n
n
n个大小为
2
2
2的集合,必选其一,问是否存在满足限制条件的组合。
以
i
i
i表示选择第一个,
i
+
n
i+n
i+n表示选择第二个,建图找矛盾。
限制
1
1
1:选择要不同。(通过找相同可以确定要连的边)
void work_1(int x,int y){
if(ve[x][0]==ve[y][0]){ // x的第一个和y的第二个相同
t[x].push_back(y+n);
t[y].push_back(x+n);
}
if(ve[x][0]==ve[y][1]){
t[x].push_back(y);
t[y+n].push_back(x+n);
}
if(ve[x][1]==ve[y][0]){
t[x+n].push_back(y+n);
t[y].push_back(x);
}
if(ve[x][1]==ve[y][1]){
t[x+n].push_back(y);
t[y+n].push_back(x);
}
}
限制 2 2 2:选择要相同。(通过找不同可以确定要连的边)
void work_2(int x,int y){
if(ve[x][0]!=ve[y][0]){
t[x].push_back(y+n);
t[y].push_back(x+n);
}
if(ve[x][0]!=ve[y][1]){
t[x].push_back(y);
t[y+n].push_back(x+n);
}
if(ve[x][1]!=ve[y][0]){
t[x+n].push_back(y+n);
t[y].push_back(x);
}
if(ve[x][1]!=ve[y][1]){
t[x+n].push_back(y);
t[y+n].push_back(x);
}
}
建完图缩点判断即可,注意初始化。
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=1e4+10;
int n,m;
int a[N],op[N],l[N],r[N];
vector<int> ve[N*3];
vector<int> t[N*3];
int dfn[N*2],low[N*2],vis[N*2],bel[N*2];
stack<int> p;
int ti=0,pos=0;
void init(){
for(int i=0;i<=n*2;i++){
ve[i].clear();
t[i].clear();
dfn[i]=low[i]=0,vis[i]=0,bel[i]=0;
}
for(int i=1;i<=n;i++){
if(a[i]==1){
ve[i].push_back(1);
ve[i].push_back(2);
}
else if(a[i]==2){
ve[i].push_back(2);
ve[i].push_back(3);
}
else{
ve[i].push_back(3);
ve[i].push_back(1);
}
}
while(!p.empty()){
p.pop();
}
ti=0,pos=0;
}
void work_1(int x,int y){
if(ve[x][0]==ve[y][0]){
t[x].push_back(y+n);
t[y].push_back(x+n);
}
if(ve[x][0]==ve[y][1]){
t[x].push_back(y);
t[y+n].push_back(x+n);
}
if(ve[x][1]==ve[y][0]){
t[x+n].push_back(y+n);
t[y].push_back(x);
}
if(ve[x][1]==ve[y][1]){
t[x+n].push_back(y);
t[y+n].push_back(x);
}
}
void work_2(int x,int y){
if(ve[x][0]!=ve[y][0]){
t[x].push_back(y+n);
t[y].push_back(x+n);
}
if(ve[x][0]!=ve[y][1]){
t[x].push_back(y);
t[y+n].push_back(x+n);
}
if(ve[x][1]!=ve[y][0]){
t[x+n].push_back(y+n);
t[y].push_back(x);
}
if(ve[x][1]!=ve[y][1]){
t[x+n].push_back(y);
t[y+n].push_back(x);
}
}
void tarjan(int u){
p.push(u),vis[u]=1;
low[u]=dfn[u]=++ti;
for(auto it:t[u]){
if(!dfn[it]){
tarjan(it);
low[u]=min(low[u],low[it]);
}
else if(vis[it]){
low[u]=min(low[u],dfn[it]);
}
}
if(dfn[u]==low[u]){
++pos; int s;
do{
s=p.top(); p.pop();
vis[s]=0,bel[s]=pos;
}while(s!=u);
}
}
bool work(){
for(int i=1;i<=m;i++){
if(op[i]){
work_1(l[i],r[i]);
}
else{
work_2(l[i],r[i]);
}
}
for(int i=0;i<=n*2;i++){
if(!dfn[i]){
tarjan(i);
}
}
for(int i=1;i<=n;i++){
if(bel[i]==bel[i+n]) return 0;
}
return 1;
}
int main(){
guo312;
int t,re=0; cin>>t;
while(t--){
cin>>n>>m; ++re;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
cin>>l[i]>>r[i]>>op[i];
}
init();
if(work()){
cout<<"Case #"<<re<<": "<<"yes"<<endl;
}
else{
cout<<"Case #"<<re<<": "<<"no"<<endl;
}
}
return 0;
}