您的位置:首页 > 其它

POJ 1733 Parity game(路径压缩并查集+离散化)

2014-03-12 23:46 225 查看
POJ 1733 Parity game(路径压缩并查集+离散化)
http://poj.org/problem?id=1733



题意:
有一个由0或1组成的长度为N的串,现在给你K条该串的信息如:
1 2 even
表示连续字符区间[1,2]之间的字符有偶数个1。
3 4 odd 表示连续字符区间[3,4]之间的字符有奇数个1。
现在问你给的K条信息是否存在矛盾。假设存在矛盾且第一条矛盾信息为第i+1条,那么请输出i(即输出最大的前i条不矛盾的信息的这个最大i)。
分析:
首先对于每个输入的区间[u,v],我们把他改成(u-1,v]这个半开半闭的区间。然后令u-1和v做为并查集中的两个个节点。并查集每个节点维护下列信息:
F[i]:表示i节点的父节点编号(父节点编号>i)。
S[i]:表示i节点到其父节点的这个半开半闭区间(i,F[i]]内的1的个数(0表偶数个,1表奇数个)。

通过findset(u)我们可以让u直接连在根节点下面,并且更新S[u]值表示(u,根]这个区间1的属性。
如果u-1与v此时不在同一个分量中,那么我们可以知道(u-1,F[u-1]]区间和(v,F[v]]区间1的属性且我们知道(u-1,v]区间的1属性,那么我们可以推算出(F[u-1],F[v]](假设F[u-1]<F[v])区间的属性,进而合并F[u-1]与F[v]的连通分量。注意:合并两个连通分量的时候,我们始终保持编号大的节点作为父亲,编号小的节点作为儿子(虽然下面的代码并没有遵照这个约定,因为就算随便合并也可以,但是需要验证较多情况)。
至此,本题的并查集部分就完成了。
由于只有5000条语句,但是却有最大a为10亿,我们并查集没必要去申请10亿的数组。所以我们将预先读入所有输入数据对(u,v,type)且存储(u-1,v,type)这种三元组,然后将所有的u-1和v排序重新从1到X编号(即用map重新映射到数轴上)。然后用上面分析的并查集处理即可。
举例如下:
原始输出为:[2 8] even [2 7] odd

转换之后为:(1,8] even (1,7] odd

重新映射之后为:(1,3] even (1,2] odd
原来区间(7,8]之间为odd,现在同样区间(2,3]之间为odd。(2,3]区间不是指整数2到整数3之间而是代值第2个端点(值7)到到第3个端点(值8)之间为odd。
AC代码:110ms 由map实现哈希表

<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
const int MAXN=10000+100;
int F[MAXN];
int S[MAXN];
int findset(int i)
{
    if(F[i]==-1)return i;
    int temp = findset(F[i]);
    S[i] =S[i]^S[F[i]];
    return F[i]=temp;
}
map<int ,int>mp;
int tot=0;
int insert(int x)
{
    if(mp.find(x)==mp.end())mp[x]=tot++;
    return mp[x];
}
int main()
{
    int n,m,k;
    while(scanf("%d",&n)==1)
    {
        memset(F,-1,sizeof(F));
        memset(S,0,sizeof(S));
        scanf("%d",&m);
        k=m;
        for(int i=0; i<m; i++)
        {
            int u,v;
            char str[10];
            scanf("%d%d%s",&u,&v,str);
            if(k<m)continue;
            u=insert(u-1);
            v=insert(v);
            int temp;
            if(str[0]=='e')//获取(u,v]之间的奇偶性
                temp=0;
            else if(str[0]=='o')
                temp=1;

            int fu=findset(u);
            int fv=findset(v);
            if(fu==fv)
            {
                int t = S[u]^S[v];
                if(t!=temp)
                    k=min(k,i);
            }
            else if(fu!=fv)
            {
                F[fu]=fv;
                S[fu]=S[u]^S[v]^temp;
            }
        }
        printf("%d\n",k);
    }
    return 0;
}</span>


AC代码: 32ms由HASHMAP实现

<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10000+100;
int F[MAXN];
int S[MAXN];
int findset(int i)
{
    if(F[i]==-1)return i;
    int temp = findset(F[i]);
    S[i] =S[i]^S[F[i]];
    return F[i]=temp;
}
/*
//********哈希模板①*********
#include<map>
map<int ,int>mp;
int tot=0;
int insert(int x)
{
    if(mp.find(x)==mp.end())mp[x]=tot++;
    return mp[x];
}
//********哈希模板①*********
*/
//********哈希模板②*********
const int HASH=10007;
struct HASHMAP
{
    int head[HASH];
    int next[MAXN];
    int state[MAXN];
    int size;
    void init()
    {
        memset(head,-1,sizeof(head));
        size=0;
    }
    int push(int st)
    {
        int h=st%HASH;
        for(int i=head[h];i!=-1;i=next[i])
        {
            if(state[i]==st)
            {
                return i;
            }
        }
        state[size]=st;
        next[size]=head[h];
        head[h]=size++;
        return size-1;
    }
}hm;
//********哈希模板②*********

int main()
{
    int n,m,k;
    while(scanf("%d",&n)==1)
    {
        hm.init();
        memset(F,-1,sizeof(F));
        memset(S,0,sizeof(S));
        scanf("%d",&m);
        k=m;
        for(int i=0; i<m; i++)
        {
            int u,v;
            char str[10];
            scanf("%d%d%s",&u,&v,str);
            if(k<m)continue;
            u=hm.push(u-1);
            v=hm.push(v);
            int temp;
            if(str[0]=='e')//获取(u,v]之间的奇偶性
                temp=0;
            else if(str[0]=='o')
                temp=1;

            int fu=findset(u);
            int fv=findset(v);
            if(fu==fv)//相同连通分量,求值
            {
                int t = S[u]^S[v];
                if(t!=temp)
                    k=min(k,i);
            }
            else if(fu!=fv)//不同连通分量,合并
            {
                F[fu]=fv;
                S[fu]=S[u]^S[v]^temp;
            }
        }
        printf("%d\n",k);
    }
    return 0;
}
</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: