图论——2SAT
SRM464 DIV1 500pt:
比较裸滴,二分+2SAT判定。由于数据量很小,floyd足矣~
View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
usingnamespace std;
class ColorfulDecoration
{
public:
conststaticint inf =1000000000;
bool map[105][105];
int abs(int x)
{
if(x <0) x =-x;
return x;
}
int getMaximum(vector <int> xa, vector <int> ya, vector <int> xb, vector <int> yb)
{
int i, j, k, l, r, mid, x1, y1, x2, y2, n = xa.size();
int ans;
l =0, r = inf;
while(l <= r)
{
mid = (l+r) >>1;
memset(map, false, sizeof(map));
for(i =0; i < n+n; i++)
for(j = i+1; j< n+n; j++)
if(i%n != j%n)
{
x1 = (i < n) ? xa[i] : xb[i-n];
y1 = (i < n) ? ya[i] : yb[i-n];
x2 = (j < n) ? xa[j] : xb[j-n];
y2 = (j < n) ? ya[j] : yb[j-n];
if(abs(x1-x2)<mid && abs(y1-y2)<mid)
{
map[i][(j<n)? j+n:j-n] =true;
map[j][(i<n)? i+n:i-n] =true;
}
}
for(k =0; k < n+n; k++)
for(i =0; i < n+n; i++)
{
if(i == k) continue;
for(j =0; j < n+n; j++)
if(j != k)
map[i][j] = map[i][j] || (map[i][k] && map[k][j]);
}
for(i =0; i < n; i++)
if(map[i][i+n] && map[i+n][i])
break;
if(i == n)
{
ans = mid;
l = mid +1;
}
else r = mid-1;
}
return ans;
}
};
pku2749:
部分限定关系已经给出来了,只是距离那个地方不是很好办。
首先二分距离limit,然后把事先给定的约束关系建好,如果a,b不能共存则a->b+n , b->a+n, a+n->b, b+n->a;如果a,b必须共存,则a->b, b->a, a+n->b+n, b+n->a+n。
然后距离约束方面分4中情况:
if(dis1[i]+dis1[j] > limit) map[i][j+n] = map[j][i+n] =true;
if(dis2[i]+dis2[j] > limit) map[i+n][j] = map[j+n][i] =true;
if(dis1[i]+dd+dis2[j] > limit) map[i][j] = map[j+n][i+n] =true;
if(dis2[i]+dd+dis1[j] > limit) map[i+n][j+n] = map[j][i] =true;
View Code
#include <iostream>
#include <cstdio>
#include <cstring>
usingnamespace std;
constint N =1010;
constint inf =10000000;
struct node
{
int x, y;
}a[N], b[N];
int n, dd, A, B, sx1, sy1, sx2, sy2, dis1[N<<1], dis2[N<<1];
bool map[N][N];
int ct, top, depth, index[N], stack[N], d[N], low[N];
bool instack[N];
int Abs(int x)
{
if(x <0) x =-x;
return x;
}
void dfs(int u)
{
int i, x;
instack[u] =true;
stack[++top] = u;
d[u] = low[u] = depth++;
for(i =1; i <= n+n; i++)
if(map[u][i])
{
if(d[i] ==-1)
{
dfs(i);
low[u] = min(low[u], low[i]);
}
else
{
if(instack[i]) low[u] = min(low[u], d[i]);
}
}
if(d[u] == low[u])
{
ct++;
while(top)
{
x = stack[top--];
index[x] = ct;
instack[x] =false;
if(x == u) break;
}
}
}
bool check(int limit)
{
int i, j, x, y;
memset(map, false, sizeof(map));
for(i =1; i <= n; i++)
for(j =1; j <= n; j++)
if(i != j)
{
if(dis1[i]+dis1[j] > limit) map[i][j+n] = map[j][i+n] =true;
if(dis2[i]+dis2[j] > limit) map[i+n][j] = map[j+n][i] =true;
if(dis1[i]+dd+dis2[j] > limit) map[i][j] = map[j+n][i+n] =true;
if(dis2[i]+dd+dis1[j] > limit) map[i+n][j+n] = map[j][i] =true;
}
for(i =1; i <= A; i++)
{
x = a[i].x, y = a[i].y;
map[x][y+n] =true;
map[y][x+n] =true;
map[x+n][y] =true;
map[y+n][x] =true;
}
for(i =1; i <= B; i++)
{
x = b[i].x, y = b[i].y;
map[x][y] = map[y][x] =true;
map[x+n][y+n] = map[y+n][x+n] =true;
}
depth = ct = top =0;
memset(d, -1, sizeof(d));
memset(instack, false, sizeof(instack));
for(i =1; i <= n+n; i++)
if(d[i] ==-1)
dfs(i);
for(i =1; i <= n; i++)
if(index[i] == index[i+n])
returnfalse;
returntrue;
}
int main()
{
int i, x, y, l, r, mid, ans;
scanf("%d%d%d", &n, &A, &B);
scanf("%d%d%d%d", &sx1, &sy1, &sx2, &sy2);
dd = Abs(sx1-sx2)+Abs(sy1-sy2);
for(i =1; i <= n; i++)
{
scanf("%d%d", &x, &y);
dis1[i] = Abs(x-sx1)+Abs(y-sy1);
dis2[i] = Abs(x-sx2)+Abs(y-sy2);
}
for(i =1; i <= A; i++)
{
scanf("%d%d", &x, &y);
a[i].x = x, a[i].y = y;
map[x][y+n] =true;
map[y][x+n] =true;
map[x+n][y] =true;
map[y+n][x] =true;
}
for(i =1; i <= B; i++)
{
scanf("%d%d", &x, &y);
b[i].x = x, b[i].y = y;
map[x][y] = map[y][x] =true;
map[x+n][y+n] = map[y+n][x+n] =true;
}
l =0, r = inf;
if(!check(inf)) ans =-1;
else
{
while(l <= r)
{
mid = (l+r) >>1;
if(check(mid))
{
ans = mid;
r = mid-1;
}
else l = mid+1;
}
}
printf("%d\n", ans);
return0;
}
pku2723:
这个题。。。还是相对来说比较裸一点的2-SAT吧~首先,最多可以打开几道门可以二分答案。然后怎样判定能不能打开limit扇门呢?假设对于给定的钥匙对有某一对是(a, b),如果后面门上有一对锁是(b, c),假设选了key a,就由a向c连一条边,意思是如果选了key a,那么必定要选key c,因为b在选完a后会消失,如此建图直接2-SAT就可以了。
View Code
#include <iostream>
#include <cstdio>
#include <cstring>
usingnamespace std;
constint N =1050;
struct node
{
int x, y;
}key[N], lock[N<<1];
int n, m;
bool map[N<<1][N<<1];
int ct, top, depth, d[N<<1], low[N<<1], index[N<<1], stack[N<<1];
bool instack[N<<1];
void dfs(int u)
{
int i, x;
instack[u] =true;
stack[++top] = u;
d[u] = low[u] = depth++;
for(i =0; i < n+n; i++)
if(map[u][i])
{
if(d[i] ==-1)
{
dfs(i);
low[u] = min(low[u], low[i]);
}
else
{
if(instack[i])
low[u] = min(low[u], d[i]);
}
}
if(low[u] == d[u])
{
ct++;
while(top)
{
x = stack[top--];
instack[x] =false;
index[x] = ct;
if(x == u) break;
}
}
}
bool check(int limit)
{
int i, j;
memset(map, false, sizeof(map));
for(i =0; i < n; i++)
{
for(j =0; j <= limit; j++)
{
if(lock[j].x == key[i].y) map[key[i].x][lock[j].y] =true;
if(lock[j].y == key[i].y) map[key[i].x][lock[j].x] =true;
}
for(j =0; j <= limit; j++)
{
if(lock[j].x == key[i].x) map[key[i].y][lock[j].y] =true;
if(lock[j].y == key[i].x) map[key[i].y][lock[j].x] =true;
}
}
ct = top= depth =0;
memset(d, -1, sizeof(d));
memset(instack, false, sizeof(instack));
for(i =0; i < n+n; i++)
if(d[i] ==-1)
dfs(i);
for(i =0; i < n; i++)
if(index[key[i].x] == index[key[i].y])
returnfalse;
returntrue;
}
int main()
{
int i, l, r, mid, ans;
while(scanf("%d%d", &n, &m) != EOF)
{
if(n==0&& m==0) break;
for(i =0; i < n; i++) scanf("%d%d", &key[i].x, &key[i].y);
for(i =0; i < m; i++) scanf("%d%d", &lock[i].x, &lock[i].y);
l =0, r = m-1;
ans =-1;
while(l <= r)
{
mid = (l+r) >>1;
if(check(mid))
{
ans = mid;
l = mid+1;
}
else r = mid-1;
}
printf("%d\n", ans+1);
}
return0;
}
pku3683:
这个,建图比较好建,不过输出的过程用的代码可能有点多。。。注意输出时婚礼的顺序要跟输入一样,偶这个白痴竟然给他排序了,刚开始还找不出原因。。。。。
View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
usingnamespace std;
constint N =1010;
struct node
{
int s, t, d;
}p[N];
int n;
int ct, depth, top, index[N<<1], d[N<<1], low[N<<1], stack[N<<1];
bool instack[N<<1], map[N<<1][N<<1], g[N<<1][N<<1];
int tot, et[N<<1], color[N<<1], op[N<<1];
bool visit[N<<1];
vector <int> ans;
void initData()
{
int i, j, x, y, l1, r1, l2, r2;
scanf("%d", &n);
for(i =0; i < n; i++)
{
scanf("%d:%d", &x, &y);
p[i].s = x*60+y;
scanf("%d:%d", &x, &y);
p[i].t = x*60+y;
scanf("%d", &p[i].d);
}
memset(map, false, sizeof(map));
for(i =0; i < n; i++)
for(j =0; j < n; j++)
{
if(i == j) continue;
l1 = p[i].s, r1 = p[i].s+p[i].d, l2 = p[j].s, r2 = p[j].s+p[j].d;
if(l1==l2 && r1==r2) map[i][j+n] =true;
if((l1>l2 && l1<r2) || (r1>l2 && r1<r2)) map[i][j+n] =true;
if((l2>l1 && l2<r1) || (r2>l1 && r2<r1)) map[i][j+n] =true;
l1 = p[i].s, r1 = p[i].s+p[i].d, l2 = p[j].t-p[j].d, r2 = p[j].t;
if(l1==l2 && r1==r2) map[i][j] =true;
if((l1>l2 && l1<r2) || (r1>l2 && r1<r2)) map[i][j] =true;
if((l2>l1 && l2<r1) || (r2>l1 && r2<r1)) map[i][j] =true;
l1 = p[i].t-p[i].d, r1 = p[i].t, l2 = p[j].s, r2 = p[j].s+p[j].d;
if(l1==l2 && r1==r2) map[i+n][j+n] =true;
if((l1>l2 && l1<r2) || (r1>l2 && r1<r2)) map[i+n][j+n] =true;
if((l2>l1 && l2<r1) || (r2>l1 && r2<r1)) map[i+n][j+n] =true;
l1 = p[i].t-p[i].d, r1 = p[i].t, l2 = p[j].t-p[j].d, r2 = p[j].t;
if(l1==l2 && r1==r2) map[i+n][j] =true;
if((l1>l2 && l1<r2) || (r1>l2 && r1<r2)) map[i+n][j] =true;
if((l2>l1 && l2<r1) || (r2>l1 && r2<r1)) map[i+n][j] =true;
}
}
void dfs(int u)
{
int i, x;
d[u] = low[u] = depth++;
stack[++top] = u;
instack[u] =true;
for(i =0; i < n+n; i++)
if(map[u][i])
{
if(d[i] ==-1)
{
dfs(i);
low[u] = min(low[u], low[i]);
}
else
{
if(instack[i])
low[u] = min(low[u], d[i]);
}
}
if(low[u] == d[u])
{
ct++;
while(top)
{
x = stack[top--];
instack[x] =false;
index[x] = ct;
if(x == u) break;
}
}
}
void buildNewGraph()
{
int i, j;
memset(g, false, sizeof(g));
for(i =0; i < n+n; i++)
for(j =0; j < n+n; j++)
if(map[i][j])
g[index[i]][index[j]] =true;
for(i =1; i <= ct; i++)
for(j = i+1; j <= ct; j++)
swap(g[i][j], g[j][i]);
for(i =0; i < n; i++)
{
op[index[i]] = index[i+n];
op[index[i+n]] = index[i];
}
}
void transDfs(int u)
{
int i;
visit[u] =true;
for(i =1; i <= ct; i++)
if(!visit[i] && g[u][i])
transDfs(i);
et[++tot] = u;
}
void colorDfs(int u)
{
int i;
color[u] =0;
for(i =1; i <= ct; i++)
if(color[i]==-1&& g[u][i])
colorDfs(i);
}
void generateAns()
{
int i;
memset(visit, false, sizeof(visit));
tot =0;
for(i =1; i <= ct; i++)
if(!visit[i])
transDfs(i);
memset(color, -1, sizeof(color));
for(i = ct; i >0; i--)
if(color[et[i]] ==-1)
{
color[et[i]] =1;
colorDfs(op[et[i]]);
}
}
void printAns()
{
int i, pos, x1, y1, x2, y2, len = ans.size();
for(i =0; i < len; i++)
{
pos = ans[i];
if(pos < n)
{
x1 = p[pos].s/60, y1 = p[pos].s %60;
x2 = (p[pos].s+p[pos].d)/60, y2 = (p[pos].s+p[pos].d)%60;
}
else
{
pos -= n;
x1 = (p[pos].t-p[pos].d)/60, y1 = (p[pos].t-p[pos].d)%60;
x2 = p[pos].t/60, y2 = p[pos].t%60;
}
printf("%d%d:%d%d %d%d:%d%d\n", x1/10, x1%10, y1/10, y1%10, x2/10, x2%10, y2/10, y2%10);
}
}
void solve()
{
int i;
depth = top = ct =0;
memset(d, -1, sizeof(d));
memset(instack, false, sizeof(instack));
for(i =0; i < n+n; i++)
if(d[i] ==-1)
dfs(i);
for(i =0; i < n; i++)
if(index[i] == index[i+n])
break;
if(i < n) printf("NO\n");
else
{
printf("YES\n");
buildNewGraph();
generateAns();
ans.clear();
for(i =0; i < n; i++)
if(color[index[i]] ==1)
ans.push_back(i);
else ans.push_back(i+n);
//sort(ans.begin(), ans.end());
printAns();
}
}
int main()
{
initData();
solve();
return0;
}