1 条题解

  • 0
    @ 2025-8-24 21:23:54

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 热言热语
    try { hard } catch (dream) {} finally { AFO } —— PinkRabbit 是信仰

    搬运于2025-08-24 21:23:53,当前版本为作者最后更新于2017-07-26 16:55:13,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    主要的算法是欧拉路。

    题目要求每条木棍都用过,同颜色的两端可以相接,如果没有字符串处理,几乎是一道欧拉路的模板题

    把每种颜色看做一个点,木棍看做连接两种颜色的无向边,整个问题就转化成了求这个图是否存在欧拉路。

    对于点的编号,可以采用字典树或者用STL里的unordered_map(map会超时)。重要:建议不选STL,非常慢……

    接下来就是欧拉路的判定。

    首先图必须是联通的。楼下给出了用dfs的方法,这里给出用并查集的方法。

    对于所有的点建立一个并查集。对于每条边,尝试把它两端的点合并,并记录有效合并(即合并前两个点不在同一组中)的次数。

    设点(注意不是边)的数量为N,有效合并次数为M,则当且仅当M==N-1时图是联通的。下面给出简单说明:

    如果图是联通图,并查集就只有一个组。而初始有N个组,每次有效合并会减少一个组,最后只剩一个组,所以有效合并次数M=N-1。

    其次(也是最后),图中奇数度数的点的个数必须为0(最后回到出发点)或2(一个点出发,另一个点结束)。对此,输入时记录每个点度数,最后全部扫一遍即可。

    代码

    核心部分代码如下:

    #include <stdio.h>
    #define N 500010//题目中说最多有250000条边,也就是最多有500000个点
    int n=0,deg[N];char s[15];//n:点数(颜色数),deg:每个点度数
    /*求编号部分(getid)*/
    //...
    /*并查集*/
    int fa[N];
    inline int find(int a) {
        return fa[a]?fa[a]=find(fa[a]):a;
    }
    inline bool join(int a,int b) {//有效合并返回true,无效返回false 
        int x=find(a),y=find(b);
        if(x==y) return false;
        fa[x]=y;return true;
    }
    /********************/
    inline bool check() {
        int x,y,cnt=0;
        while(~scanf("%s",s)) {
            x=getid(s);
            scanf("%s",s);
            y=getid(s);//getid求编号 
            if(join(x,y)) ++cnt;//记录有效合并次数 
            ++deg[x];++deg[y];//统计度数 
        }
        if(cnt<n-1) return false;//判联通:只有当cnt==n-1时是联通的 
        cnt=0;//记录奇数度点的个数
        for(int i=1;i<=n;++i) if((deg[i]&1)&&++cnt>2) return false;//扫一遍颜色的度,奇数度点个数>2就退出 
        return true;
    }
    int main() {
        puts(check()?"Possible":"Impossible");
        return 0;
    }
    

    求编号的部分(两种做法):

    /*1.Trie/字典树*/
    int nd=1,root=1;struct node{int son[26],num;}t[1000010];
    int getid(const char *s) {
        int k=root;char c;
        for(int i=0;s[i];++i) {
            c=s[i]-'a';
            if(!t[k].son[c]) t[k].son[c]=++nd;//动态开点
            k=t[k].son[c];
        }
        if(!t[k].num) t[k].num=++n;
        return t[k].num;
    }
    /*2.unordered_map*/
    #include <string>
    #include <unordered_map>
    using namespace std;
    unordered_map<string,int> M;
    int getid(const char *s) {
        return M[s]?M[s]:M[s]=++n;
    }
    
    • 1

    信息

    ID
    331
    时间
    1000ms
    内存
    125MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者