训练指南 P325 例题
2-SAT问题+二分。
题目的数据范围小,所以用朴素的算法解2-SAT能过。
tarjan的SCC算法判2-SAT
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#define MAXN 2200
#define MAXN_2 4400
using namespace std;
int min(int a,int b)
{
return a>b?b:a;
}
struct TwoSAT
{
int n;
vector<int> g[MAXN_2];
int ng[MAXN_2][MAXN_2];
bool vis[MAXN_2];
int mem[MAXN],lm;
int dfn[MAXN_2];
int low[MAXN_2];
int stack[MAXN_2];
bool ins[MAXN_2];
int color[MAXN_2];
int s_top;
int tag;
int lc;
void init(int num)
{
int i;
n=num;
for (i=0; i<(n<<1); i++)
{
g[i].clear();
}
memset(vis,false,sizeof(vis));
}
void add_clause(int x,int bx,int y,int by)
{
x=(x<<1)+bx;
y=(y<<1)+by;
g[x^1].push_back(y);
g[y^1].push_back(x);
}
bool dfs(int x)
{
int i;
if (vis[x^1] == true)
return false;
if (vis[x] == true)
return true;
mem[lm]=x;
lm++;
vis[x]=true;
for (i=0; i<g[x].size(); i++)
{
if (dfs(g[x][i]) == false)
return false;
}
return true;
}
bool solveByBruteForce()
{
int i;
for (i=0; i<(n<<1); i+=2)
{
if (vis[i] == false && vis[i+1] == false)
{
lm=0;
if (dfs(i) == false)
{
while (lm != 0)
{
vis[mem[lm-1]]=false;
lm--;
}
if (dfs(i+1) == false)
return false;
}
}
}
return true;
}
void tarjan(int u)
{
int v,i;
dfn[u]=tag;
low[u]=tag;
tag++;
stack[s_top]=u;
s_top++;
ins[u]=true;
for (i=0; i<g[u].size(); i++)
{
v=g[u][i];
if (dfn[v] == -1)
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if (dfn[v] != -1 && ins[v] == true)
{
low[u]=min(low[u],dfn[v]);
}
}
if (dfn[u] == low[u])
{
do
{
v=stack[s_top-1];
s_top--;
color[v]=lc;
ins[v]=false;
}while (v != u);
lc++;
}
}
bool solveWithSCC()
{
int i,j,v,u;
memset(dfn,-1,sizeof(dfn));
s_top=0;
tag=1;
lc=1;
for (i=0; i<(n<<1); i++)
{
if (dfn[i] == -1)
tarjan(i);
}
for (i=0; i<(n<<1); i+=2)
{
if (color[i] == color[i+1])
return false; //A pair founded illegal
}
return true;
}
};
TwoSAT sat;
int a[MAXN][2];
int abs(int x)
{
return x>0?x:-x;
}
bool check(int n,int x)
{
// printf("%d\n",x);
int i,j,k,l;
sat.init(n);
for (i=0; i<n; i++)
{
for (j=0; j<2; j++)
{
for (k=i+1; k<n; k++)
{
for (l=0; l<2; l++)
{
if (abs(a[i][j]-a[k][l]) < x)
{
sat.add_clause(i,j^1,k,l^1); //л╚╬╜╣Дак
}
}
}
}
}
return sat.solveWithSCC();
}
int main()
{
int n,i,l,r,mid;
while (scanf("%d",&n) != EOF)
{
l=0;
r=0;
for (i=0; i<n; i++)
{
scanf("%d%d",&a[i][0],&a[i][1]);
r=r>a[i][1]?r:a[i][1];
}
while (l < r)
{
// printf("l=%d r=%d\n",l,r);
mid=l+((r-l+1)>>1);
if (check(n,mid) == true)
{
l=mid;
}
else
{
r=mid-1;
}
}
printf("%d\n",l);
}
}
这个是朴素算法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#define MAXN 2200
#define MAXN_2 4400
using namespace std;
struct TwoSAT
{
int n;
vector<int> g[MAXN_2];
bool vis[MAXN_2];
int mem[MAXN],lm;
void init(int num)
{
int i;
n=num;
for (i=0; i<(n<<1); i++)
{
g[i].clear();
}
memset(vis,false,sizeof(vis));
}
void add_clause(int x,int bx,int y,int by)
{
x=(x<<1)+bx;
y=(y<<1)+by;
g[x^1].push_back(y);
g[y^1].push_back(x);
}
bool dfs(int x)
{
int i;
if (vis[x^1] == true)
return false;
if (vis[x] == true)
return true;
mem[lm]=x;
lm++;
vis[x]=true;
for (i=0; i<g[x].size(); i++)
{
if (dfs(g[x][i]) == false)
return false;
}
return true;
}
bool solve()
{
int i;
for (i=0; i<(n<<1); i+=2)
{
if (vis[i] == false && vis[i+1] == false)
{
lm=0;
if (dfs(i) == false)
{
while (lm != 0)
{
vis[mem[lm-1]]=false;
lm--;
}
if (dfs(i+1) == false)
return false;
}
}
}
return true;
}
};
TwoSAT sat;
int a[MAXN][2];
int abs(int x)
{
return x>0?x:-x;
}
bool check(int n,int x)
{
// printf("%d\n",x);
int i,j,k,l;
sat.init(n);
for (i=0; i<n; i++)
{
for (j=0; j<2; j++)
{
for (k=i+1; k<n; k++)
{
for (l=0; l<2; l++)
{
if (abs(a[i][j]-a[k][l]) < x)
{
sat.add_clause(i,j^1,k,l^1); //л╚╬╜╣Дак
}
}
}
}
}
return sat.solve();
}
int main()
{
int n,i,l,r,mid;
while (scanf("%d",&n) != EOF)
{
l=0;
r=0;
for (i=0; i<n; i++)
{
scanf("%d%d",&a[i][0],&a[i][1]);
r=r>a[i][1]?r:a[i][1];
}
while (l < r)
{
// printf("l=%d r=%d\n",l,r);
mid=l+((r-l+1)>>1);
if (check(n,mid) == true)
{
l=mid;
}
else
{
r=mid-1;
}
}
printf("%d\n",l);
}
}