POJ2749 Building road
这道题真是2-SAT好题啊!!卡了我两个点才做完……垃圾POJ还不告诉我哪错了……
首先我们先花一段时间把题看懂……(其实是翻译一下),之后我们发现因为每个谷仓只能向一个中转点连边,所以他就是一个布尔变量的两个取值。然后对于每个限制条件,其实就是^嘛!我们把他转换为合取范式之后建一下图。不过怎么计算最大距离最小值呢?看到这一幕想起二分答案……然后,然后就不会了……
我们再想一下,其实2-SAT里面,每个给定的限制特别要命,因为如果要没有限制随便瞎取都能合法,然后我们要限制一个最大距离……那我们不妨把连接之后距离大于当前值的两个谷仓加一个限制,使两者不能连边,这样我们再跑一遍2-SAT判断一下当前是否合法,然后改变二分的值就可以。
具体怎么加距离的限制,如果两个点通过某种连接方式之后不合法,我们就把其中一个向另一个的否定连边(一个点连接s1,s2),比如说第一个点连向s1,第二个点连向s2,如果这样是不合法的情况的话,那么我们强制性让第一个点连s2,第二个点连s1,这样建边就可以啦。
然而说着容易做着难……代码贼拉难写+忘记判断-1+不知道怎么建边……卡了两个小时。
Source Code Problem: 2749 User: ifvisit Memory: 6176K Time: 1657MS Language: C++ Result: Accepted Source Code #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define fill(x,y) memset(x,y,sizeof(x)); #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 10005; const int N = 500005; const int INF = 1000000009; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct edge { int next,to,from; }e[N]; struct node { int x,y; }q[M]; struct relation { int a,b; }ha[M],li[M]; int n,m,g,head[M],ecnt,dfn[M],low[M],stack[M],top,scc[M],a,b,c,d,dis1[M],dis2[M],len,idx,cnt; int minn = 100000000,maxn,ans; int s1 = 2000,s2 = 2001; bool vis[M]; void add(int x,int y) { e[++ecnt].to = y; e[ecnt].from = x; e[ecnt].next = head[x]; head[x] = ecnt; } int rev(int x) { return x > n ? x - n : x + n; } int mht(int kx,int ky) { return abs(q[kx].x - q[ky].x) + abs(q[kx].y - q[ky].y); } void clear() { memset(e,0,sizeof(e)); memset(head,0,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(scc,0,sizeof(scc)); ecnt = idx = cnt = 0; } void build(int x) { rep(i,1,m) { int r1 = ha[i].a,r2 = ha[i].b; add(r1,r2+n),add(r1+n,r2),add(r2,r1+n),add(r2+n,r1); } rep(i,1,g) { int r1 = li[i].a,r2 = li[i].b; add(r1,r2),add(r2,r1),add(r1+n,r2+n),add(r2+n,r1+n); } rep(i,1,n) { rep(j,i+1,n) { int l1 = dis1[i],l2 = dis2[i],r1 = dis1[j],r2 = dis2[j]; if(l1 + r1 > x) add(i,j+n),add(j,i+n); if(l2 + r2 > x) add(i+n,j),add(j+n,i); if(l1 + r2 + len > x) add(i,j),add(j+n,i+n); if(l2 + r1 + len > x) add(i+n,j+n),add(j,i); } } } void tarjan(int x) { dfn[x] = low[x] = ++idx; stack[++top] = x,vis[x] = 1; for(int i = head[x];i;i = e[i].next) { if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]); else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]); } if(low[x] == dfn[x]) { int p; cnt++; while((p = stack[top--])) { scc[p] = cnt,vis[p] = 0; if(p == x) break; } } } void solve() { int l = 0,r = 8000000; while(l < r) { bool flag = 0; int mid = (l+r) >> 1; clear(),build(mid); rep(i,1,n<<1) if(!dfn[i]) tarjan(i); rep(i,1,n) { if(scc[i] == scc[i+n]) { flag = 1; break; } } if(flag) l = mid + 1; else r = mid; } if(l == 0 || l == 8000000) printf("-1\n"); else printf("%d\n",l); } int main() { n = read(),m = read(),g = read(); q[s1].x = read(),q[s1].y = read(),q[s2].x = read(),q[s2].y = read(); len = abs(q[s2].y-q[s1].y) + abs(q[s2].x-q[s1].x); rep(i,1,n) { q[i].x = read(),q[i].y = read(); dis1[i] = mht(i,s1),dis2[i] = mht(i,s2); } rep(i,1,m) ha[i].a = read(),ha[i].b = read(); rep(i,1,g) li[i].a = read(),li[i].b = read(); solve(); return 0; }
当你意识到,每个上一秒都成为永恒。