• 【UOJ #210】【UER #6】寻找罪犯


    题目描述

    有n个人分为好人和坏人,说了m句话。好人不会说假话,坏人至多说一句谎话。求出一组解,满足要求。

    题解

    利用2-SAT拆点,一个人拆成两个点,表示他是好人和坏人。然而这样的话边数是m^2的,所以用前/后缀和优化构图即可。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 const int N = 1e6 + 10;
      5 const int M = 3e6 + 10;
      6 inline int read()
      7 {
      8     char ch = getchar();int x = 0, f = 1;
      9     while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
     10     while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) - '0' + ch; ch = getchar();}
     11     return x * f;
     12 }
     13 int n, m;
     14 int h[N], e[M], ne[M], idx;
     15 int dfn[N], low[N], num, in[N], stac[N], top, pre[N];
     16 int c[N], cnt;
     17 
     18 void add(int a, int b)
     19 {
     20     e[idx] = b;
     21     ne[idx] = h[a];
     22     h[a] = idx++;
     23 }
     24 
     25 int crm(int x, int f)
     26 {
     27     return x + n * f;
     28 }
     29 
     30 int word(int x, int f)
     31 {
     32     return n + n + x + m * f;
     33 }
     34 
     35 void tarjan(int u)
     36 {
     37     stac[++ top] = u;
     38     dfn[u] = low[u] = ++ num;
     39     in[u] = 1;
     40     for (int i = h[u]; ~i; i = ne[i])
     41     {
     42         int j = e[i];
     43         if(!dfn[j])
     44         {
     45             tarjan(j);
     46             low[u] = min(low[u], low[j]);
     47         }
     48         else if(in[j])
     49             low[u] = min(low[u], dfn[j]);
     50     }
     51     if(low[u] == dfn[u])
     52     {
     53         int z;
     54         cnt ++;
     55         do{
     56             z = stac[top --];
     57             c[z] = cnt;
     58             in[z] = 0;
     59         }while(z != u);
     60     }
     61 }
     62 
     63 
     64 int main()
     65 {
     66     memset(h, -1, sizeof(h));
     67     n = read(), m = read();
     68     for (int i = 1; i <= n; i ++) pre[i] = 2*m + 1;
     69     for (int i = 1; i <= m; i ++)
     70     {
     71         int x = read(), y = read(), t = read();
     72         t ^= 1;
     73         add(crm(y, t ^ 1), word(pre[x], 0)); //若这次y的身份与x说的相反,则x前面说的话都对。
     74         
     75         add(word(pre[x], 1), crm(y, t));    //若x前面说过谎话了,y的身份与x说的相符
     76 
     77         add(word(i, 0), crm(y, t));         //若说的话一直是真的,y的身份与x相符
     78         
     79         add(crm(y, t ^ 1), word(i, 1));     //若y的身份与x说的不符,x这句话是假的
     80         
     81         add(word(pre[x], 1), word(i, 1));   //前面说过假话,现在也保持说过假话的状态
     82         
     83         add(word(i, 0), word(pre[x], 0));   //现在都没说过假话,前面也没说过假话
     84         pre[x] = i;                         //更新前缀
     85     }
     86     for (int i = 1; i <= n; i ++)
     87     {
     88         add(word(pre[i], 1), crm(i, 1));    //说过假话,一定是坏人
     89         add(crm(i, 0), word(pre[i], 0));    //好人一定没说过假话
     90     }
     91     for (int i = 1; i <= (n + m) * 2; i ++)
     92             if(!dfn[i])
     93                 tarjan(i);
     94     bool flag = true;
     95     for (int i = 1; i <= n; i ++)
     96     {
     97         if(c[i] == c[i + n])
     98         {
     99             flag = false;
    100             break;
    101         }
    102     }
    103     for (int i = 1; i <= m; i ++)
    104     {
    105         if(c[n + n + i] == c[n + n + m + i])
    106         {
    107             flag = false;
    108             break;
    109         }
    110     }
    111     if(!flag)
    112     {
    113         puts("Impossible");
    114     }
    115     else
    116     {
    117         vector<int>ans;
    118         for (int i = 1; i <= n; i ++)
    119         {
    120             if(c[i] > c[i + n])
    121                 ans.push_back(i);
    122         }
    123         cout << ans.size() << '
    ';
    124         for (int i = 0; i < ans.size(); i ++)
    125         {
    126             printf("%d%c", ans[i], i == ans.size() -1?'
    ' : ' ');
    127         }
    128     }
    129 }
    View Code
  • 相关阅读:
    hdoj 1879 继续畅通工程
    hdoj 1233 还是畅通工程
    PAT-1107 Social Clusters (30 分)
    hdoj 1232 畅通工程
    POJ-3061 前缀和+二分搜索 模板题
    常见推荐系统框架
    常见的时间衰减函数
    英语中的五大基本句型
    如何获得excel文件名和工作表名
    记一次atomikos 连接池耗尽错误
  • 原文地址:https://www.cnblogs.com/xwdzuishuai/p/14032073.html
Copyright © 2020-2023  润新知