今天才会2-sat,是不是没有救了...
Anna最近在学sat2...真是心有灵犀啊...
参考链接:
http://wenku.baidu.com/view/afd6c436a32d7375a41780f2.html
方法:
假如有n对pair,每对pair只能挑选一个,有些人有矛盾,不能让他们在一起
对于p1和p2:如果有p1.x和p2.y有矛盾,即如果选择了p1.x就不能选择p2.y,即选择了p1.x就必须选择p2.x,所以就连一条边p1.x->p2.x
同理,还有一条p2.y->p1.y
无解的情况:在一定条件下,某一个人即要被选择又不能被选择
即:在图中,存在一对pair p | p.x 和 p.y属于同一个强连通分量
hdu 3062 party
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stack>
2 #include <cstdio>
3 #include <vector>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7
8 const int maxn = 2000 + 2;
9 const int maxm = 4000000 + 2;
10
11 stack<int> s;
12 bool in[maxn];
13 vector<int> G[maxn];
14 int n, m, scc, Index, dfn[maxn], low[maxn], belong[maxn];
15
16 void tarjan(int now){
17 dfn[now] = low[now] = ++ Index;
18 in[now] = true, s.push(now);
19
20 for (int i = 0, len = G[now].size(), to; i < len; i ++){
21 to = G[now][i];
22 if (!dfn[to]){
23 tarjan(to);
24 low[now] = min(low[now], low[to]);
25 }
26
27 else if (in[to])
28 low[now] = min(low[now], dfn[to]);
29 }
30
31 if (low[now] == dfn[now]){
32 ++ scc;
33
34 int u;
35 do {
36 u = s.top();
37 s.pop(), in[u] = false;
38 belong[u] = scc;
39 } while (u ^ now);
40 }
41 }
42
43 inline void init(){
44 memset(low, 0, sizeof low);
45 memset(dfn, 0, sizeof dfn);
46 memset(in, false, sizeof in);
47 Index = scc = 0;
48 while (not s.empty())
49 s.pop();
50 for (int i = 0; i < 2 * n; i ++)
51 G[i].clear();
52
53 for (int i = 0, a, b, x, y, g1, g2; i < m; i ++){
54 scanf("%d %d %d %d", &a, &b, &g1, &g2);
55
56 x = a * 2 + 1 - g1, y = b * 2 + 1 - g2;
57 a = a * 2 + g1, b = b * 2 + g2;
58
59 G[a].push_back(y), G[b].push_back(x);
60 }
61 }
62
63 inline bool two_sat(){
64 init();
65 for (int i = 0; i < n * 2; i ++)
66 if (!dfn[i])
67 tarjan(i);
68
69 for (int i = 0; i < n; i ++)
70 if (belong[i * 2] == belong[i * 2 + 1])
71 return false;
72
73 return true;
74 }
75
76 int main(){
77 while (scanf("%d %d", &n, &m) == 2)
78 puts(two_sat() ? "YES" : "NO");
79 }
poj 3678
对于每个xi,有两个选择,0还是1,建边的时候要讨论一下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stack>
2 #include <cstdio>
3 #include <vector>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7
8 const int maxl = 10;
9 const int maxn = 2000 + 2;
10
11 stack<int> s;
12 bool in[maxn];
13 char buff[maxl];
14 vector<int> G[maxn];
15 int n, m, scc, Index, low[maxn], dfn[maxn], belong[maxn];
16
17 inline void init(){
18 memset(dfn, 0, sizeof dfn);
19 memset(low, 0, sizeof low);
20 memset(in, false, sizeof in);
21 memset(belong, 0, sizeof belong);
22 scc = Index = 0;
23
24 for (int i = 0; i < n * 2; i ++)
25 G[i].clear();
26
27 while (!s.empty())
28 s.pop();
29 }
30
31 void tarjan(int x){
32 dfn[x] = low[x] = ++ Index;
33 in[x] = true, s.push(x);
34
35 for (int i = 0, to; i < G[x].size(); i ++){
36 to = G[x][i];
37
38 if (!dfn[to]){
39 tarjan(to);
40 low[x] = min(low[x], low[to]);
41 }
42
43 else if (in[to])
44 low[x] = min(low[x], dfn[to]);
45 }
46
47 if (low[x] == dfn[x]){
48 ++ scc;
49
50 int u;
51 do {
52 u = s.top();
53 s.pop(), in[u] = false;
54 belong[u] = scc;
55 } while (u ^ x);
56 }
57 }
58
59 inline bool two_sat(){
60 for (int i = 0; i < n * 2; i ++)
61 if (!dfn[i])
62 tarjan(i);
63
64 for (int i = 0; i < n; i ++)
65 if (belong[i << 1] == belong[(i << 1) | 1])
66 return false;
67
68 return true;
69 }
70
71 inline void link(int u, int v){
72 G[u].push_back(v ^ 1);
73 G[v].push_back(u ^ 1);
74 }
75
76 inline void type_and(int a, int b, int c){
77 if (c){
78 link(a << 1, b << 1);
79 link(a << 1, (b << 1) | 1);
80 link((a << 1) | 1, b << 1);
81 }
82 else
83 link((a << 1) | 1, (b << 1) | 1);
84 }
85
86 inline void type_or(int a, int b, int c){
87 if (!c){
88 link(a << 1, (b << 1) | 1);
89 link((a << 1) | 1, b << 1);
90 link((a << 1) | 1, (b << 1) | 1);
91 }
92 else
93 link(a << 1, b << 1);
94 }
95
96 inline void type_xor(int a, int b, int c){
97 if (!c){
98 link(a << 1, (b << 1) | 1);
99 link((a << 1) | 1, b << 1);
100 }
101 else {
102 link(a << 1, b << 1);//0 0
103 link((a << 1) | 1, (b << 1) | 1);
104 }
105 }
106
107 int main(){
108 while (scanf("%d %d", &n, &m) == 2){
109 init();
110
111 for (int i = 1, a, b, c; i <= m; i ++){
112 scanf("%d %d %d %s", &a, &b, &c, buff);
113
114 if (buff[0] == 'A')
115 type_and(a, b, c);
116
117 if (buff[0] == 'O')
118 type_or(a, b, c);
119
120 if (buff[0] == 'X')
121 type_xor(a, b, c);
122 }
123
124 puts(two_sat() ? "YES" : "NO");
125 }
126 }
hdu 3622 bomb
二分答案,用2-sat来check
建图的时候:先处理处每个点的距离
对于任意两轮游戏,有两个放置位置,pair_point1 = {p1, p2}, pair_point2 = {p3, p4};
如果有dis(p1, p4) < d (即有相交的面积),就有p1 -> p3, p4->p2
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cmath>
2 #include <stack>
3 #include <cstdio>
4 #include <vector>
5 #include <cstring>
6 #include <algorithm>
7 #define _d (double)
8 using namespace std;
9
10 const double eps = 1e-4;
11 const int maxn = 200 + 2;
12
13 stack<int> s;
14 bool in[maxn];
15 vector<int> G[maxn];
16 double dis[maxn][maxn];
17 int n, scc, Index, low[maxn], dfn[maxn], belong[maxn];
18
19 struct Point {
20 int x, y;
21 } p[maxn];
22
23 inline void init(){
24 memset(dfn, 0, sizeof dfn);
25 memset(low, 0, sizeof low);
26 memset(in, false, sizeof in);
27 memset(belong, 0, sizeof belong);
28 scc = Index = 0;
29
30 for (int i = 0; i < n; i ++)
31 G[i].clear();
32
33 while (!s.empty())
34 s.pop();
35 }
36
37 inline double get_dis(Point a, Point b){
38 return sqrt(_d (a.x - b.x) * (a.x - b.x) + _d (a.y - b.y) * (a.y - b.y));
39 }
40
41 inline int get_partener(int a){
42 return a % 2 == 0 ? a + 1 : a - 1;
43 }
44
45 void tarjan(int x){
46 dfn[x] = low[x] = ++ Index;
47 in[x] = true, s.push(x);
48
49 for (int i = 0, to; i < G[x].size(); i ++){
50 to = G[x][i];
51
52 if (!dfn[to]){
53 tarjan(to);
54 low[x] = min(low[x], low[to]);
55 }
56
57 else if (in[to])
58 low[x] = min(low[x], dfn[to]);
59 }
60
61 if (low[x] == dfn[x]){
62 ++ scc;
63
64 int u;
65 do {
66 u = s.top();
67 s.pop(), in[u] = false;
68 belong[u] = scc;
69 } while (u ^ x);
70 }
71 }
72
73 inline int cmp(double x){
74 if (fabs(x) < eps)
75 return 0;
76 return x < 0 ? -1 : 1;
77 }
78
79 inline bool two_sat(double r){
80 init();
81
82 double d = r + r;
83 for (int i = 0; i < n; i ++)
84 for (int j = 0; j < n; j ++)
85 if (i / 2 != j / 2 && dis[i][j] < d){
86 G[i].push_back(get_partener(j));
87 G[j].push_back(get_partener(i));
88 }
89
90 for (int i = 0; i < n; i ++)
91 if (!dfn[i])
92 tarjan(i);
93
94 for (int i = 0; i < n; i ++)
95 if (belong[i] == belong[get_partener(i)])
96 return false;
97
98 return true;
99 }
100
101 inline double search(){
102 double l = 0, r = 10000, mid;
103 while (cmp(l - r) == -1){
104 mid = (l + r) / 2.0;
105
106 if (two_sat(mid))
107 l = mid;
108 else
109 r = mid;
110 }
111
112 return l;
113 }
114
115 int main(){
116 while (~scanf("%d", &n)){
117 n *= 2;
118 for (int i = 0; i < n; i ++)
119 scanf("%d %d", &p[i].x, &p[i].y);
120
121 for (int i = 0; i < n; i ++)
122 for (int j = i + 1; j < n; j ++)
123 dis[i][j] = dis[j][i] = get_dis(p[i], p[j]);
124
125 printf("%.2f\n", search());
126 }
127 }
poj 2723
二分答案,用2-sat来check
建图的时候:把每个钥匙拆成两个点,选或者不选,编号对应choose(i)和toss(i)
对于key = {a, b},有choose(a) -> toss(b), choose(b) -> toss(a)
对于lock = {a, b},有toss(a) -> choose(b), toss(b) -> choose(a)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stack>
2 #include <cstdio>
3 #include <vector>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7
8 const int maxk = 1200 + 2;
9 const int maxn = 1024 * 4 + 2;
10
11 char ch;
12 stack<int> s;
13 bool in[maxn];
14 vector<int> G[maxn];
15 int n, m, scc, Index, dfn[maxn], low[maxn], belong[maxn];
16
17 struct Pair {
18 int a, b;
19 } key[maxk], lock[maxk << 1];
20
21 inline int next_int(){
22 do
23 ch = getchar();
24 while (!(48 <= ch && ch <= 57));
25
26 int ret = 0;
27 do {
28 ret = ret * 10 + ch - 48;
29 ch = getchar();
30 } while (48 <= ch && ch <= 57);
31
32 return ret;
33 }
34
35 void tarjan(int now){
36 dfn[now] = low[now] = ++ Index;
37 in[now] = true, s.push(now);
38
39 for (int i = 0, len = G[now].size(), to; i < len; i ++){
40 to = G[now][i];
41 if (!dfn[to]){
42 tarjan(to);
43 low[now] = min(low[now], low[to]);
44 }
45
46 else if (in[to])
47 low[now] = min(low[now], dfn[to]);
48 }
49
50 if (low[now] == dfn[now]){
51 ++ scc;
52
53 int u;
54 do {
55 u = s.top();
56 s.pop(), in[u] = false;
57 belong[u] = scc;
58 } while (u ^ now);
59 }
60 }
61
62 inline void clear(){
63 memset(low, 0, sizeof low);
64 memset(dfn, 0, sizeof dfn);
65 memset(in, false, sizeof in);
66 Index = scc = 0;
67
68 while (not s.empty())
69 s.pop();
70
71 for (int i = 0; i < 4 * n; i ++)
72 G[i].clear();
73 }
74
75 inline bool two_sat(int to){
76 clear();
77
78 for (int i = 0; i < n; i ++){
79 G[key[i].a * 2].push_back(key[i].b * 2 + 1);
80 G[key[i].b * 2].push_back(key[i].a * 2 + 1);
81 }
82
83 for (int i = 1; i <= to; i ++){
84 G[lock[i].a * 2 + 1].push_back(lock[i].b * 2);
85 G[lock[i].b * 2 + 1].push_back(lock[i].a * 2);
86 }
87
88 for (int i = 0; i < 4 * n; i ++)
89 if (!dfn[i])
90 tarjan(i);
91
92 for (int i = 0; i < 2 * n; i ++)
93 if (belong[i * 2] == belong[i * 2 + 1])
94 return false;
95 return true;
96 }
97
98 inline int search(){
99 int l = 0, r = m, mid;
100 while (l < r){
101 mid = (l + r + 1) >> 1;
102
103 if (two_sat(mid))
104 l = mid;
105 else
106 r = mid - 1;
107 }
108
109 return l;
110 }
111
112 int main(){
113 while (true){
114 n = next_int(), m = next_int();
115 if (!n && !m)
116 return 0;
117
118 for (int i = 0; i < n; i ++)
119 key[i].a = next_int(), key[i].b = next_int();
120
121 for (int i = 1; i <= m; i ++)
122 lock[i].a = next_int(), lock[i].b = next_int();
123
124 printf("%d\n", search());
125 }
126 }