HDU 4115 Eliminate the Conflict 2-sat 建图

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tawn0000/article/details/83064091

                                           HDU 4115 Eliminate the Conflict

Conflicts are everywhere in the world, from the young to the elderly, from families to countries. Conflicts cause quarrels, fights or even wars. How wonderful the world will be if all conflicts can be eliminated.
Edward contributes his lifetime to invent a 'Conflict Resolution Terminal' and he has finally succeeded. This magic item has the ability to eliminate all the conflicts. It works like this:
If any two people have conflict, they should simply put their hands into the 'Conflict Resolution Terminal' (which is simply a plastic tube). Then they play 'Rock, Paper and Scissors' in it. After they have decided what they will play, the tube should be opened and no one will have the chance to change. Finally, the winner have the right to rule and the loser should obey it. Conflict Eliminated!
But the game is not that fair, because people may be following some patterns when they play, and if the pattern is founded by others, the others will win definitely.
Alice and Bob always have conflicts with each other so they use the 'Conflict Resolution Terminal' a lot. Sadly for Bob, Alice found his pattern and can predict how Bob plays precisely. She is very kind that doesn't want to take advantage of that. So she tells Bob about it and they come up with a new way of eliminate the conflict:
They will play the 'Rock, Paper and Scissors' for N round. Bob will set up some restricts on Alice.
But the restrict can only be in the form of "you must play the same (or different) on the ith and jth rounds". If Alice loses in any round or break any of the rules she loses, otherwise she wins.
Will Alice have a chance to win?

Input

The first line contains an integer T(1 <= T <= 50), indicating the number of test cases.
Each test case contains several lines.
The first line contains two integers N,M(1 <= N <= 10000, 1 <= M <= 10000), representing how many round they will play and how many restricts are there for Alice.
The next line contains N integers B 1,B 2, ...,B N, where B i represents what item Bob will play in the i th round. 1 represents Rock, 2 represents Paper, 3 represents Scissors.
The following M lines each contains three integers A,B,K(1 <= A,B <= N,K = 0 or 1) represent a restrict for Alice. If K equals 0, Alice must play the same on A th and B th round. If K equals 1, she must play different items on Ath and Bthround.

Output

For each test case in the input, print one line: "Case #X: Y", where X is the test case number (starting with 1) and Y is "yes" or "no" represents whether Alice has a chance to win.

Sample Input

2
3 3
1 1 1
1 2 1
1 3 1
2 3 1
5 5
1 2 3 2 1
1 2 1
1 3 1
1 4 1
1 5 1
2 3 0

Sample Output

Case #1: no
Case #2: yes

        
  

Hint

'Rock, Paper and Scissors' is a game which played by two person. They should play Rock, Paper or Scissors by their hands at the same time. 
Rock defeats scissors, scissors defeats paper and paper defeats rock. If two people play the same item, the game is tied..


题意:题目是意思是两个人猜拳,石头剪刀布,n轮猜拳,Alice 知道Bob出拳规律,约定m个规则,每个规则有a,b,k. 代表:如果k == 0 ,Alice在第a次和第b次出拳必须是一样的,如果k == 1, 则必须是不一样的。Alice必须满足所有规则并且没有一轮输才算Alice最终赢,问Alice是否有机会赢。

题解:首先有由于已知Bob出拳顺序,且Alice不能输掉一轮,所以实际上Alice只有两种选择,但是这两种选择对于每一轮可能是不一样的。
当k == 0 时,如果第a轮和第b轮的选择是一样的,那么必须连边 a-b, b-a, a^1-b^1, b^1-a^1。
如果选择不一样,则必有一个共同选择,所以必须将a,b各轮不同的选择连到相同的选择,表示一旦选了不同的选择,就会选到相同的选择,这样相当于短路性质,直接将不同的选择给短路掉了。(这个性质很重要)。
当k == 1时,如果第a轮和第b轮的选择是一样的,那么必须连边 a-b^1, b-a^1, a^1-b, b^1-a。
如果选择不一样,就将a,b各轮相同的选择连到对方不同的选择。比如a : 1 2  b: 2 3, 连a2-b3  b2-a1 ,这样就防止了同时选a2,b2,如果有a2-b2就会立即触发各自的另一个选择,从而返回false。

2-sat 要想清楚逻辑关系和应该要建的对应边之间的联系。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4*2+100;
int n,m;
vector <int> G[maxn];//正向邻接表
vector <int> rG[maxn];//反向邻接表
vector <int> vs;     //拓扑序存点
int cmp[maxn]; //标号
bool used[maxn];

//Kosaraju
void dfs(int x)
{
  used[x] = true;
  for(int i = 0; i < G[x].size(); i++)
   if(!used[G[x][i]])  dfs(G[x][i]);
  vs.push_back(x);
}

void rdfs(int x, int k)
{
  used[x] = true;
  cmp[x] = k;
  for(int i = 0; i < rG[x].size(); i++)
    if(!used[rG[x][i]]) rdfs(rG[x][i],k);
}

int scc()
{
  memset(used, false , sizeof(used));
  vs.clear();
  for(int i = 0; i < n*2; i++)
     if(!used[i]) dfs(i);
  memset(used, false ,sizeof(used));
  int k = 0;
  for(int i = vs.size()-1; i >= 0; i--)
     if(!used[vs[i]])  rdfs(vs[i],++k);
  return k;
}

void add_edge(int u, int v)
{
  G[u].push_back(v);
  rG[v].push_back(u);
  //cout << u << " - "<< v << endl;
}

int b[maxn];
int c[maxn][2];

int main()
{
  int T;
  int cs = 0;
  scanf("%d",&T);
  while(T--)
  {
    scanf("%d%d",&n,&m);
    bool t = true;
    for(int i = 0; i < 2*n; i++) {G[i].clear();rG[i].clear();}
    for(int i = 0; i < n; i++)
      {
        scanf("%d",&b[i]);
        if(b[i] == 1)  c[i][0] = 1,c[i][1] = 2;
        else if(b[i] == 2) c[i][0] = 2,c[i][1] = 3;
        else {c[i][0] = 1,c[i][1] = 3;}
      }
    for(int i = 0; i < m; i++)
    {
      int u,v,p;
      scanf("%d%d%d",&u,&v,&p);
      u--,v--;
      if(p == 0)
        {
          if(b[u] == b[v])
          {
            add_edge(u*2,v*2);
            add_edge(v*2,u*2);
            add_edge(u*2+1,v*2+1);
            add_edge(v*2+1,u*2+1);
          }
          else
          {
            if(c[u][0] == c[v][0]) {add_edge(u*2+1,u*2);add_edge(v*2+1,v*2);}
            if(c[u][0] == c[v][1]) {add_edge(u*2+1,u*2);add_edge(v*2,v*2+1);}
            if(c[u][1] == c[v][0]) {add_edge(u*2,u*2+1);add_edge(v*2+1,v*2);}
            if(c[u][1] == c[v][1]) {add_edge(u*2,u*2+1);add_edge(v*2,v*2+1);}
          }
        }
      else
      {
         if(b[u] == b[v])
         {
           add_edge(u*2,v*2+1);
           add_edge(v*2,u*2+1);
           add_edge(u*2+1,v*2);
           add_edge(v*2+1,u*2);
         }
         else
         {
           if(c[u][0] == c[v][0]) {add_edge(u*2,v*2+1);add_edge(v*2,u*2+1);}
           if(c[u][0] == c[v][1]) {add_edge(u*2,v*2);add_edge(v*2+1,u*2+1);}
           if(c[u][1] == c[v][0]) {add_edge(u*2+1,v*2+1);add_edge(v*2,u*2);}
           if(c[u][1] == c[v][1]) {add_edge(u*2+1,v*2);add_edge(v*2+1,u*2);}
         }
      }
    }
  scc();
  for(int i = 0; i < n; i++)
    if(cmp[i*2] == cmp[i*2+1]) {t = false;break;}
  printf("Case #%d: ",++cs);
  if(t) printf("yes\n");
  else printf("no\n");
 }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/Tawn0000/article/details/83064091
今日推荐