3207 -- Ikki's Story IV - Panda's Trick (poj.org)http://poj.org/problem?id=32072-SAT 模板题
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#define x first
#define y second
using namespace std;
typedef pair<int,int> pii ;
const int N = 1100 , M = 1e6 ;
int n,m ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
pii q[N] ;
bool check(int a,int b,int c,int d){ // 检查是否相交
if(c < b && b < d && a < c || c < a && a < d && b < d) return 1;
return 0;
}
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}
void tarjan(int u){
dfn[u] = low[u] = ++ timestamp ;
stk[++top] = u ,ins[u] = 1 ;
for(int i = h[u] ; ~ i ; i = ne[i]){
int j = e[i] ;
if(!dfn[j]){
tarjan(j) ;
low[u] = min(low[u],low[j]) ;
}
else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
}
if(low[u] == dfn[u]){
int y ;
id_cnt ++ ;
do{
y = stk[top--],ins[y] = 0 ,id[y] = id_cnt ;
}while(y != u) ;
}
}
int main(){
scanf("%d%d",&n,&m) ;
memset(h,-1,sizeof h) ;
for(int i = 0 ; i < m ; i ++) scanf("%d%d",&q[i].x,&q[i].y) ;
for(int i = 0 ; i < m ; i++){
for(int j = i + 1; j < m ; j++){
int a = q[i].x,b = q[i].y ;
int c = q[j].x,d = q[j].y ;
if(a > b) swap(a,b) ;
if(c > d) swap(c,d) ;
if(check(a,b,c,d)){
add(i,j+m) ;
add(i+m,j) ;
add(j,i+m) ;
add(j+m,i) ;
}
}
}
for(int i = 0 ; i < 2 * m ; i++){
if(!dfn[i]){
tarjan(i) ;
}
}
bool flag = 1 ;
for(int i = 0 ; i < m ; i++){
if(id[i] == id[i+m]){
flag = 0 ;
break ;
}
}
if(flag) puts("panda is telling the truth...") ;
else puts("the evil panda is lying again") ;
return 0;
}
3683 -- Priest John's Busiest Day (poj.org)http://poj.org/problem?id=3683
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 2100 , M = 5e6 + 100 ;
// 暴力枚举所有的时间
int n ;
struct node
{
int s,t,d ;
}q[N];
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}
bool is_overlap(int a,int b,int c,int d){
if(b <= c || d <= a) return 0 ;
return 1;
}
void tarjan(int u){
dfn[u] = low[u] = ++ timestamp ;
stk[++top] = u,ins[u] = 1;
for(int i = h[u] ; ~ i ; i= ne[i]){
int j = e[i] ;
if(!dfn[j]){
tarjan(j) ;
low[u] = min(low[u],low[j]) ;
}
else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
}
if(low[u] == dfn[u]){
int y ;
id_cnt ++ ;
do{
y = stk[top--],ins[y] = 0 ,id[y] = id_cnt ;
}while(y != u) ;
}
}
int main(){
scanf("%d",&n) ;
memset(h,-1,sizeof h) ;
for(int i = 0 ; i < n ; i++){
int h,m,d ;
scanf("%d:%d",&h,&m) ;
q[i].s = h * 60 + m ;
scanf("%d:%d",&h,&m) ;
q[i].t = h * 60 + m ;
scanf("%d",&d) ;
q[i].d = d ;
}
for(int i = 0 ; i < n ; i ++){
for(int j = i + 1 ; j < n ; j++){
node a = q[i],b =q[j] ;
if(is_overlap(a.s,a.s+a.d,b.s,b.s+b.d)) add(i,j+n),add(j,i+n) ;
if(is_overlap(a.s,a.s+a.d,b.t-b.d,b.t)) add(i,j),add(j+n,i+n) ;
if(is_overlap(a.t-a.d,a.t,b.s,b.s+b.d)) add(i+n,j+n),add(j,i) ;
if(is_overlap(a.t-a.d,a.t,b.t-b.d,b.t)) add(i+n,j),add(j+n,i) ;
}
}
for(int i = 0 ; i < 2 * n ; i++){
if(!dfn[i])
tarjan(i) ;
}
for(int i = 0 ; i < n ; i++){
if(id[i] == id[i+n]){
puts("NO") ;
return 0 ;
}
}
puts("YES") ;
for(int i = 0 ; i < n ; i++){
node a = q[i] ;
if(id[i] < id[i+n]) printf("%02d:%02d %02d:%02d\n",a.s / 60 ,a.s % 60,(a.s + a.d) / 60 ,(a.s + a.d) % 60) ;
else printf("%02d:%02d %02d:%02d\n",(a.t - a.d) / 60 ,(a.t - a.d) % 60 ,a.t / 60 ,a.t % 60) ;
}
return 0;
}
3678 -- Katu Puzzle (poj.org)http://poj.org/problem?id=3678板子题
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 210 ,M = 2e6 + 100 ;
int n,m ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}
void tarjan(int u){
dfn[u] = low[u] = ++timestamp ;
stk[++top] = u,ins[u] = 1 ;
for(int i = h[u] ;~ i ; i = ne[i]){
int j = e[i] ;
if(!dfn[j]){
tarjan(j) ;
low[u] = min(low[u],low[j]) ;
}
else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
}
if(low[u] == dfn[u]){
int y ;
id_cnt ++ ;
do{
y = stk[top--],ins[y] = 0,id[y] = id_cnt ;
}while(y != u) ;
}
}
int main(){
scanf("%d%d",&n,&m) ;
memset(h,-1,sizeof h) ;
while(m--){
int a,b,c ;
char op[10] ;
scanf("%d%d%d %s",&a,&b,&c,op) ;
if(*op == 'A'){
if(c) add(a+n,a),add(b+n,b) ; // 两个都成立
else add(a,b+n),add(b,a+n) ; // !a || !b
}
else if(*op == 'O'){
if(c) add(a+n,b),add(b+n,a) ;
else add(a,a+n),add(b,b+n) ;
}
else{
if(c) add(a,b+n),add(a+n,b),add(b+n,a) ,add(b,a+n);
else add(a,b),add(a+n,b+n),add(b,a),add(b+n,a+n) ;
}
}
for(int i = 0 ; i < 2 * n ; i++){
if(!dfn[i])
tarjan(i) ;
}
for(int i = 0 ; i < n ; i++){
if(id[i+n] == id[i]){
puts("NO") ;
return 0 ;
}
}
puts("YES") ;
return 0;
}
3648 -- Wedding (poj.org)http://poj.org/problem?id=3648
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 210 , M = 2e4 + 100 ;
int n,m ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
char ans[N] ;
void init(){
idx = timestamp = id_cnt = 0 ;
memset(h,-1,sizeof h) ;
memset(dfn,0,sizeof dfn) ;
memset(ins,0,sizeof ins) ;
}
int get(char x,int a,int t){
if(x == 'h'){
if(!t) return a ;
return 2 * n + a ;
}
else{
if(!t) return n + a;
return 3 * n + a ;
}
}
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void tarjan(int u){
dfn[u] = low[u] = ++ timestamp ;
stk[++top] = u,ins[u] = 1;
for(int i = h[u] ;~i ;i = ne[i]){
int j = e[i] ;
if(!dfn[j]){
tarjan(j) ;
low[u] = min(low[u],low[j]) ;
}
else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
}
if(low[u] == dfn[u]){
int y ;
id_cnt++ ;
do{
y = stk[top--],ins[y] = 0,id[y] = id_cnt ;
}while(y != u) ;
}
}
int main(){
while(scanf("%d%d",&n,&m),n || m){
init() ;
while(m--){
int a,b ;
char x,y ;
scanf("%d%c%d%c",&a,&x,&b,&y) ;
// 分析,将与新娘坐在一侧视为0,与新郎坐在一侧视为1
// 这是有通奸关系,所以不能同时坐在新娘对面
add(get(x,a,1),get(y,b,0)),add(get(y,b,1),get(x,a,0)) ;
}
for(int i = 0 ; i < n ; i ++){
// 两个不能坐在同一侧,
char x = 'h',y = 'w' ;
add(get(x,i,0),get(y,i,1)),add(get(y,i,0),get(x,i,1)) ;
}
add(get('w',0,1),get('w',0,0)) ;
for(int i = 0 ; i < 4 * n; i++)
if(!dfn[i])
tarjan(i) ;
bool flag = 1 ;
for(int i = 0 ; i < 2 * n ; i ++){
if(id[i] == id[i + 2 * n]){
flag = 0 ;
break ;
}
}
if(!flag){
puts("bad luck") ;
continue ;
}
for(int i = 0 ; i < 2 * n; i++){
if(id[i] < id[i + 2 * n]){
if(i < n) ans[i] = 'h' ;
else ans[i-n] = 'w' ;
}
}
for(int i = 1 ; i < n ; i++){
printf("%d%c ",i,ans[i]) ;
}
puts("") ;
}
return 0;
}
2723 -- Get Luffy Out (poj.org)http://poj.org/problem?id=2723
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#define x first
#define y second
using namespace std;
typedef pair<int,int> pii ;
const int N = 4100 , M = 2 * N ;
// http://poj.org/problem?id=2723
// 由题目分析可得到,当可以开开i个门,那么一定可以开开i-1个门,那么说开门数量是具有单调性的
// 由于具有单调性,所以可以使用二分来解决
// 那么是二分的话,据需要写一个合适的检查函数
// 那么检查函数需要找到选前mid个门能否成立
// 那么这就转化为一个2-SAT问题,是否成立了。
// 每对钥匙a,b是选了 a -> !b ,b -> !a ;
// 每对门a,b是a || b, !a - > b,!b - > a;
int n,m ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
pii key[N],q[N] ;
void init(){
idx = timestamp = id_cnt = 0 ;
memset(h,-1,sizeof h) ;
memset(dfn,0,sizeof dfn) ;
}
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}
void tarjan(int u){
dfn[u] = low[u] = ++ timestamp ;
stk[++top] = u ,ins[u] = 1 ;
for(int i = h[u] ; ~ i ; i = ne[i]){
int j = e[i] ;
if(!dfn[j]){
tarjan(j) ;
low[u] = min(low[u],low[j]) ;
}
else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
}
if(low[u] == dfn[u]){
int y ;
id_cnt ++ ;
do{
y =stk[top--],ins[y] = 0,id[y] = id_cnt ;
}while(y != u) ;
}
}
bool check(int m){
init() ;
for(int i = 0 ; i < n ; i++){
add(key[i].x,key[i].y + 2 * n),add(key[i].y ,key[i].x + 2 * n) ;
}
for(int i = 0 ; i < m; i++){
add(q[i].x + 2 * n,q[i].y),add(q[i].y + 2 * n,q[i].x) ;
}
for(int i = 0 ; i < 4 * n ; i++){
if(!dfn[i])
tarjan(i) ;
}
for(int i = 0 ; i < 2 * n ; i++){
if(id[i] == id[i + 2 * n]){
return 0 ;
}
}
return 1 ;
}
int main(){
while(scanf("%d%d",&n,&m),n || m){
for(int i = 0 ; i < n ; i ++) scanf("%d%d",&key[i].x,&key[i].y) ;
for(int i = 0 ; i < m ; i++) scanf("%d%d",&q[i].x,&q[i].y) ;
int l = 1 , r = m ;
while(l < r){
int mid = l + r + 1 >> 1 ;
if(check(mid)) l = mid ;
else r = mid - 1;
}
printf("%d\n",l) ;
}
return 0;
}
2749 -- Building roads (poj.org)http://poj.org/problem?id=2749
数组二分
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#define x first
#define y second
using namespace std;
typedef pair<int,int> pii ;
const int N = 1100 , M = 2e6 + 100 ;
// 同上一题
// 都是二分答案
// 这里二分的时候从数组中二分,由于是整数值,也可以直接二分
int n,A,B,dist_s1_s2 ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
pii obv[N],fir[N] ;
pii q[N],dist[N],s1,s2 ;
vector<int> nums ;
int get_dist(pii &a,pii &b){
return abs(a.x-b.x) + abs(a.y-b.y) ;
}
void init(){
idx = timestamp = id_cnt = 0 ;
memset(h,-1,sizeof h) ;
memset(dfn,0,sizeof dfn) ;
}
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}
void tarjan(int u){
dfn[u] = low[u] = ++ timestamp ;
stk[++top] = u,ins[u] = 1 ;
for(int i = h[u] ;~ i ; i = ne[i]){
int j = e[i] ;
if(!dfn[j]){
tarjan(j) ;
low[u] = min(low[u],low[j]) ;
}
else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
}
if(low[u] == dfn[u]){
int y ;
id_cnt ++ ;
do{
y = stk[top--],ins[y] = 0,id[y] = id_cnt ;
}while(y != u) ;
}
}
bool check(int mid){
init() ;
for(int i = 0 ; i < A ; i++){
int a = obv[i].x,b = obv[i].y ;
add(a,b+n),add(a+n,b) ;
add(b,a+n),add(b+n,a) ;
}
for(int i = 0 ; i < B; i++){
int a = fir[i].x ,b = fir[i].y ;
add(a,b),add(a+n,b+n) ;
add(b,a),add(b+n,a+n) ;
}
for(int i = 0 ; i < n ; i ++){
for(int j = i + 1 ; j < n ; j ++){
int a = i + 1 ,b = j + 1 ;
if(dist[i].x + dist[j].x > nums[mid]) add(a,b+n),add(b,a+n) ;
if(dist[i].y + dist[j].y > nums[mid]) add(a+n,b),add(b+n,a) ;
if(dist[i].x + dist[j].y + dist_s1_s2 > nums[mid]) add(a,b),add(b+n,a+n) ;
if(dist[i].y + dist[j].x + dist_s1_s2 > nums[mid]) add(b,a),add(a+n,b+n) ;
}
}
for(int i = 1 ; i <= 2 * n ; i++){
if(!dfn[i])
tarjan(i) ;
}
for(int i = 1 ; i <= n ; i++){
if(id[i] == id[i+n]) return 0 ;
}
return 1 ;
}
int main(){
scanf("%d%d%d",&n,&A,&B) ;
scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y) ;
dist_s1_s2 = get_dist(s1,s2) ;
for(int i = 0 ; i < n ; i++){
scanf("%d%d",&q[i].x,&q[i].y) ;
dist[i].x = get_dist(q[i],s1) ;
dist[i].y = get_dist(q[i],s2) ;
}
for(int i = 0 ; i < n ; i ++){
for(int j = i + 1 ; j < n ; j ++){
nums.push_back(dist[i].x+dist[j].x) ; // 分为四种情况,都连接s1,都连接s2,第一个连接s1第二个连接s2,第一个连接s2,第二个连接s1
nums.push_back(dist[i].y+dist[j].y) ;
nums.push_back(dist[i].x+dist[j].y + dist_s1_s2) ;
nums.push_back(dist[i].y+dist[j].x + dist_s1_s2) ;
}
}
for(int i = 0 ; i < A ; i ++) scanf("%d%d",&obv[i].x,&obv[i].y) ;
for(int i = 0 ; i < B ; i++) scanf("%d%d",&fir[i].x,&fir[i].y) ;
sort(nums.begin(),nums.end()) ;
nums.erase(unique(nums.begin(),nums.end()),nums.end()) ;
nums.push_back(1e9) ;
//for(int i : nums) cout << i << endl ;
int l = 0, r = nums.size() - 1;
while(l < r){
int mid = l + r >> 1 ;
if(check(mid)) r = mid ;
else l = mid + 1 ;
}
nums.back() = -1 ;
printf("%d\n",nums[l]) ;
return 0;
}
直接二分
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#define x first
#define y second
using namespace std;
typedef pair<int,int> pii ;
const int N = 1100 , M = 2e6 + 100 ;
int n,A,B,dist_s1_s2 ;
int h[N],e[M],ne[M],idx ;
int dfn[N],low[N],timestamp ;
int stk[N],id[N],top,id_cnt ;
bool ins[N] ;
pii obv[N],fir[N] ;
pii q[N],dist[N],s1,s2 ;
vector<int> nums ;
int get_dist(pii &a,pii &b){
return abs(a.x-b.x) + abs(a.y-b.y) ;
}
void init(){
idx = timestamp = id_cnt = 0 ;
memset(h,-1,sizeof h) ;
memset(dfn,0,sizeof dfn) ;
}
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}
void tarjan(int u){
dfn[u] = low[u] = ++ timestamp ;
stk[++top] = u,ins[u] = 1 ;
for(int i = h[u] ;~ i ; i = ne[i]){
int j = e[i] ;
if(!dfn[j]){
tarjan(j) ;
low[u] = min(low[u],low[j]) ;
}
else if(ins[j]) low[u] = min(low[u],dfn[j]) ;
}
if(low[u] == dfn[u]){
int y ;
id_cnt ++ ;
do{
y = stk[top--],ins[y] = 0,id[y] = id_cnt ;
}while(y != u) ;
}
}
bool check(int mid){
init() ;
for(int i = 0 ; i < A ; i++){
int a = obv[i].x,b = obv[i].y ;
add(a,b+n),add(a+n,b) ;
add(b,a+n),add(b+n,a) ;
}
for(int i = 0 ; i < B; i++){
int a = fir[i].x ,b = fir[i].y ;
add(a,b),add(a+n,b+n) ;
add(b,a),add(b+n,a+n) ;
}
for(int i = 0 ; i < n ; i ++){
for(int j = i + 1 ; j < n ; j ++){
int a = i + 1 ,b = j + 1 ;
if(dist[i].x + dist[j].x > mid) add(a,b+n),add(b,a+n) ;
if(dist[i].y + dist[j].y > mid) add(a+n,b),add(b+n,a) ;
if(dist[i].x + dist[j].y + dist_s1_s2 > mid) add(a,b),add(b+n,a+n) ;
if(dist[i].y + dist[j].x + dist_s1_s2 > mid) add(b,a),add(a+n,b+n) ;
}
}
for(int i = 1 ; i <= 2 * n ; i++){
if(!dfn[i])
tarjan(i) ;
}
for(int i = 1 ; i <= n ; i++){
if(id[i] == id[i+n]) return 0 ;
}
return 1 ;
}
int main(){
scanf("%d%d%d",&n,&A,&B) ;
scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y) ;
dist_s1_s2 = get_dist(s1,s2) ;
for(int i = 0 ; i < n ; i++){
scanf("%d%d",&q[i].x,&q[i].y) ;
dist[i].x = get_dist(q[i],s1) ;
dist[i].y = get_dist(q[i],s2) ;
}
// for(int i = 0 ; i < n ; i ++){
// for(int j = i + 1 ; j < n ; j ++){
// nums.push_back(dist[i].x+dist[j].x) ; // 分为四种情况,都连接s1,都连接s2,第一个连接s1第二个连接s2,第一个连接s2,第二个连接s1
// nums.push_back(dist[i].y+dist[j].y) ;
// nums.push_back(dist[i].x+dist[j].y + dist_s1_s2) ;
// nums.push_back(dist[i].y+dist[j].x + dist_s1_s2) ;
// }
// }
for(int i = 0 ; i < A ; i ++) scanf("%d%d",&obv[i].x,&obv[i].y) ;
for(int i = 0 ; i < B ; i++) scanf("%d%d",&fir[i].x,&fir[i].y) ;
// sort(nums.begin(),nums.end()) ;
// nums.erase(unique(nums.begin(),nums.end()),nums.end()) ;
// nums.push_back(1e9) ;
//for(int i : nums) cout << i << endl ;
int l = 0, r = 1e9;
while(l < r){
int mid = l + r >> 1 ;
if(check(mid)) r = mid ;
else l = mid + 1 ;
}
// nums.back() = -1 ;
if(l == 1e9) l = -1 ;
printf("%d\n",l) ;
return 0;
}