uvalive 3713 Astronauts

题意:

现在要安排一些宇航员去星球勘探。有3个星球,分别是J第一大的月亮A,J第二大的月亮B,S第一大的月亮C。

规定年轻的宇航员不能去A,年长的宇航员不能去B,C任何人都可以去。

现在有一些宇航员之间有矛盾,他们不能去相同的星球。

现在问可否安排出这样的方案满足条件,如果有,那么就输出每个宇航员去的星球,没有就说明不可能。

思路:

2-SAT问题

对于年轻的宇航员,去B为真,去C为假

对于年长的宇航员,去A为真,去C为假

首先考虑对于不同类型的宇航员i和j,只要他们不在同一个星球C上就满足条件,即Xi ∨ Xj为真就满足,利用这个条件加边

但是对于同一个类型的宇航员i和j,他们不在同一个星球才满足条件,这个条件要求Xi 和Xj当中必定一个为真,一个为假,那么如何刻画呢?那就是两个当中至少一个为真,至少有一个为假,用符号表示即为Xi V Xj,┐Xi ∨┐Xj 两个条件同时为真,那么进行两次加边就可以了。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <vector>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 const int maxn = 100005;
  9 int a[maxn];
 10 
 11 struct twosat
 12 {
 13     int n;
 14     vector<int> g[maxn*2];
 15     bool mark[maxn*2];
 16     int s[maxn*2],c;
 17     
 18     bool dfs(int x)
 19     {
 20         if (mark[x^1]) return false;
 21         if (mark[x]) return true;
 22         
 23         mark[x] = true;
 24         
 25         s[c++] = x;
 26         
 27         for (int i = 0;i < g[x].size();i++)
 28         {
 29             if (!dfs(g[x][i])) return false;
 30         }
 31         
 32         return true;
 33     }
 34     
 35     void init(int n)
 36     {
 37         this -> n = n;
 38         
 39         for (int i = 0;i <= n * 2;i++) g[i].clear();
 40         
 41         memset(mark,0,sizeof(mark));
 42     }
 43     
 44     void add_clause(int x,int xval,int y,int yval)
 45     {
 46         x = 2 * x + xval;
 47         y = 2 * y + yval;
 48         
 49         g[x^1].push_back(y);
 50         g[y^1].push_back(x);
 51     }
 52     
 53     bool solve()
 54     {
 55         for (int i = 0;i < 2 * n;i += 2)
 56         {
 57             if (!mark[i] && !mark[i+1])
 58             {
 59                 c = 0;
 60                 
 61                 if (!dfs(i))
 62                 {
 63                     while (c > 0) mark[s[--c]] = 0;
 64                     
 65                     if (!dfs(i+1)) return false;
 66                 }
 67             }
 68         }
 69         
 70         return true;
 71     }
 72 } twosat;
 73 
 74 int main()
 75 {
 76     int n,m;
 77     //int kase = 0;
 78     
 79     while (scanf("%d%d",&n,&m) != EOF)
 80     {
 81         if (n == 0 && m == 0) break;
 82         
 83         int ave = 0;
 84         
 85         for (int i = 0;i < n;i++)
 86         {
 87             scanf("%d",&a[i]);
 88             ave += a[i];
 89         }
 90         
 91         //ave /= n;
 92         
 93         twosat.init(n);
 94         
 95         for (int i = 0;i < m;i++)
 96         {
 97             int x,y;
 98             
 99             scanf("%d%d",&x,&y);
100             
101             x--,y--;
102             
103             //if (x == y) continue;
104             
105             if (a[x] * n < ave && a[y] * n < ave)
106             {
107                 twosat.add_clause(x,1,y,1);
108                 twosat.add_clause(x,0,y,0);
109             }
110             else if (a[x] * n >= ave && a[y] * n >= ave)
111             {
112                 twosat.add_clause(x,1,y,1);
113                 twosat.add_clause(x,0,y,0);
114             }
115             else
116             {
117                 twosat.add_clause(x,1,y,1);
118             }
119         }
120         
121         if (twosat.solve())
122         {
123             for (int i = 0;i < n;i++)
124             {
125                 if (a[i] * n >= ave)
126                 {
127                     if (twosat.mark[2*i+1]) printf("A\n");
128                     else printf("C\n");
129                 }
130                 else
131                 {
132                     if (twosat.mark[2*i+1]) printf("B\n");
133                     else printf("C\n");
134                 }
135             }
136         }
137         else
138         {
139             printf("No solution.\n");
140         }
141         
142         //printf("\n");
143     }
144     
145     return 0;
146 }

 

posted @ 2018-04-12 17:35  qrfkickit  阅读(190)  评论(0编辑  收藏  举报