您的位置:首页 > 其它

HDOJ/HDU 3715 2-sat+二分 2010年成都赛区

2011-07-24 02:08 399 查看
//题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3715
题目:
[align=left]Problem Description[/align] Here is a procedure's pseudocode:

go(int dep, int n, int m)
begin
output the value of dep.
if dep < m and x[a[dep]] + x[b[dep]] != c[dep] then go(dep + 1, n, m)
end

In this code n is an integer. a, b, c and x are 4 arrays of integers. The index of array always starts from 0. Array a and b consist of non-negative integers smaller than n. Array x consists of only 0 and 1. Array c consists of only 0, 1 and 2. The lengths of array a, b and c are m while the length of array x is n. Given the elements of array a, b, and c, when we call the procedure go(0, n, m) what is the maximal possible value the procedure may output?
[align=left]Input[/align] There are multiple test cases. The first line of input is an integer T (0 < T ≤ 100), indicating the number of test cases. Then T test cases follow. Each case starts with a line of 2 integers n and m (0 < n ≤ 200, 0 < m ≤ 10000). Then m lines of 3 integers follow. The i-th(1 ≤ i ≤ m) line of them are ai-1 ,bi-1 and ci-1 (0 ≤ ai-1, bi-1 < n, 0 ≤ ci-1 ≤ 2).
[align=left]Output[/align] For each test case, output the result in a single line.
[align=left]Sample Input[/align]
3
2 1
0 1 0
2 1
0 0 0
2 2
0 1 0
1 1 2

[align=left]Sample Output[/align]
1
1
2

[align=left]Author[/align] CAO, Peng
[align=left]Source[/align] The 2010 ACM-ICPC Asia Chengdu Regional Contest
[align=left]Recommend[/align] zhouzeyong
题意就不在多说了
回想起当年在场外围观的那一场惊心动魄的区域赛。。如今一年也快过去了。。
我是否达到了当年去参加那次区域赛的学长们的能力。。每每念及此,都感觉到非常大的压力
当年的学长毕业的毕业,退役的退役,今年终于轮到我们这一届
2009级的站出来了。。

先说说这个题目。
这个题,先开始看到的时候不知到如何下手,后来看到x的取值仅仅就只有1,0两种情况,而且c的取值也仅仅只有0,1,2
三种取值,于是诱导我们想到了判断可行性的2-sat
但是2-sat仅仅只是判断了可行性,但是我们要求的是输出最大深度。
故我们可以去枚举每一个可能的深度。当然如果直接从0到m进行线性的枚举,然后每次tarjan求强联通,肯定会超时超到爆。。。
所以标准的方法是利用二分答案的方法。利用2-sat来验证可行性。这样大大优化了程序的速度。
建图的方法:
令a=0,a'=1,b=0,b'=1

if(c[i]==0)那么a和b必然矛盾,于是连接边:a->b'同理连接b->a'
if(c[i]==1)那么a和b' a'和b必然矛盾,那么连接,a->b,a'->b',b->a,b'->a'
if(c[i]==2)那么a'和b'必然矛盾,于是:a'->b,b'->a

这样我们就连好了一副图。于是在对着个图进行强连通分量判断就可以AC了。

我的代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<stack>
#define maxn 20005

using namespace std;

int Index,cnt;
int a[maxn],b[maxn],c[maxn];
vector<int>map[maxn];
int belong[maxn],dfn[maxn],low[maxn];
bool used[maxn],instack[maxn];
stack<int>s;

void init(int n)
{
int i;
for(i=0;i<=2*n;i++)
map[i].clear();
while(!s.empty())
s.pop();
memset(used,0,sizeof(used));
memset(instack,0,sizeof(instack));
memset(dfn,-1,sizeof(dfn));
memset(belong,0,sizeof(belong));
memset(low,0,sizeof(low));
cnt=0,Index=0;
}

void build_map(int mid,int n)
{
int i;
init(n);
for(i=1;i<=mid;i++)
{
if(c[i]==0)
{
map[a[i]].push_back(b[i]+n);
map[b[i]].push_back(a[i]+n);
}
if(c[i]==1)
{
map[a[i]].push_back(b[i]);
map[b[i]].push_back(a[i]);
map[a[i]+n].push_back(b[i]+n);
map[b[i]+n].push_back(a[i]+n);
}
if(c[i]==2)
{
map[a[i]+n].push_back(b[i]);
map[b[i]+n].push_back(a[i]);
}
}
}

int min(int a,int b)
{
if(a>b)
return b;
else
return a;
}

void tarjan(int u)
{
int i,v;
Index++;
dfn[u]=Index;
low[u]=Index;
used[u]=true;
instack[u]=true;
s.push(u);
for(i=0;i<map[u].size();i++)
{
v=map[u][i];
if(!used[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
cnt++;
do
{
v=s.top();
s.pop();
belong[v]=cnt;
instack[v]=false;
}
while(u!=v);
}
}

bool judge(int n,int m,int mid)
{
int i;
build_map(mid,n);
for(i=0;i<2*n;i++)
if(dfn[i]==-1)
tarjan(i);
for(i=0;i<n;i++)
{
if(belong[i]==belong[i+n])
return false;
}
return true;
}

void solve(int n,int m)
{
int left,right,mid,ans;
left=0,right=m;
while(left<=right)
{
mid=(left+right)>>1;
if(judge(n,m,mid))
{
ans=mid;
left=mid+1;
}
else
right=mid-1;
}
printf("%d\n",ans);
}

int main()
{
int t,i,n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]);
solve(n,m);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: