[題解](水/最短路)出题人大战工作人员

P2616 --出题人大战工作人员

时间限制:1000MS      内存限制:131072KB    无   无

题目描述(fight.cpp)

邪恶的出题人在NOIP 夏令营的图论专场里出了一道丧题,他想要让可爱的小朋友们都被题目虐得惨惨的~

这道题目是这个样子的:

“小A拥有一个超大型的煤__________矿区,这个矿区由若干挖矿点组成,挖矿点之间通过双向通道连接。由于布局问题,这个矿区有一些挖矿点如果发生塌方,就会导致一部分挖矿点与外界的联系被切断。

“为了避免这种情况,小A决定在他的矿区建造一些安全竖井。给每个挖矿点都建造一个安全竖井自然是可以的,但是这样要消耗太多的资金。小A想要建造尽量少的安全竖井,并且确保无论哪一个挖矿点发生塌方,其余挖矿点的人都能够通过安全竖井逃离到达地面。

“现在你需要帮助小A算出最少需要多少个安全竖井,以及在最少的条件下有多少种可行的建造方案。”

善良的工作人员在看到了题目之后觉得这题目太可怕了。为了防止世界被破坏,同时守护世界的和平!他决定对邪恶的出题人提出谴责!

但是出题人完全不理会工作人员的谴责,仍然决定使用这道题目来虐小朋友们。

终于,工作人员无法忍受出题人的残忍行为,决定对出题人提出决斗!

出题人找来了一本成语字典,上面有非常多的成语。他要求工作人员进行一次成语接龙,并且只能使用这本字典上的成语。并且还要求这本字典上的第一个成语是最开始的第一个成语。

两个成语能够接起来当且仅当后面一个成语的第一个字和前面一个成语的最后一个字相同。

如果工作人员能够接到字典里的最后一个成语(并不需要字典里的成语都用过),那么出题人就答应给小朋友们换一道题目。

但是,邪恶的出题人怎么会让工作人员轻松完成这个挑战呢?他给每个成语都进行了256 位的AES 加密!

然而,伟大的工作人员也不是吃素的,他可以在没有私钥的情况下破解这个加密!可是这是需要时间的。

为了尽快打倒出题人,让小朋友们的题目变得简单,请你帮助工作人员计算一下,他最快需要多少时间破解这个密码完成接龙?

输入格式(fight.in)

输入包含多组数据。

每组数据第一行一个整数n,表示字典中成语的数量(若为0则表示结束)。

接下来n 行,每行先是一个整数,表示破解这个成语的加密需要的时间。

之后是这个成语。成语的每个字符用16 进制编码(仅包含'0'~'9','A'~'F'),4 个十六进制数字表示一个字符,最多不超过100 个字符。

输出格式(fight.out)

每组数据输出一行,如果可以接到最后一个成语则输出最短时间,如果不能则输出-1。

样例输入

5

5 0000AED882931111

5 111148312222

7 2222AAAA3333

15 1111EEEE3333

4 3333ABCD1234

0

样例输出

21

数据规模与约定

对于30% 的数据满足,n <= 20

对于100% 的数据满足,n <= 1 000,破解密码所需时间是不超过1 000

000 的正整数,数据组数不超过20,单词长度不超过100。

【样例解释】

第一个成语是“0000AED882931111”,这一共有4 个字符,分别是“0000”,“AED8”,“8293” 和 “1111”。

工作人员应该这样进行接龙:

“0000AED882931111”

“111148312222”

“2222AAAA3333”

“3333ABCD1234”


 

一道大水題,然而考場上因為沒把前後4個字符哈希下來結果沒做......

如果把前後4個字符看做點,那麼每個成語就是一條邊,

但是不能從第一個成語的開頭跑,(顯然)可能會走其他邊,結尾同理

所以答案為w[1]+w[cnt]+d[end]

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
int n,st,ed;
char s[105];
int d[100000],v[100000];
int head[100000],cnt;
struct node{
    int v,w,nxt;
}e[100000];
void add(int u,int v,int w){
    e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
int getfr(){
    int ans=0;
    for(int i=0;i<4;i++)
    ans=(ans<<4)+(isdigit(s[i])?s[i]-'0':s[i]-'A'+10);
    return ans;
}
int getbk(int len){
    int ans=0;
    for(int i=len-4;i<len;i++)
    ans=(ans<<4)+(isdigit(s[i])?s[i]-'0':s[i]-'A'+10);
    return ans;
}
void spfa(int s){
    queue<int>q;
    d[s]=0;v[s]=1;q.push(s);
    while(!q.empty()){
        int x=q.front();q.pop();v[x]=0;
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].v,z=e[i].w;
            if(d[y]>d[x]+z){
                d[y]=d[x]+z;
                if(!v[y])q.push(y),v[y]=1;
            }
        }
    }
}
int main()
{
    while(scanf("%d",&n)){
        if(n==0)break;
        memset(e,0,sizeof(e));
        memset(d,0x3f,sizeof(d));
        memset(head,0,sizeof(head));
        cnt=0;
        
        int u,v,w,len;
        scanf("%d%s",&w,s);
        len=strlen(s);
        u=getfr();v=getbk(len);
        add(u,v,w);
        st=v;
        for(int i=2;i<n;i++){
            scanf("%d%s",&w,s);
            len=strlen(s);
            u=getfr();v=getbk(len);
            add(u,v,w);
        }
        scanf("%d%s",&w,s);
        len=strlen(s);
        u=getfr();v=getbk(len);
        add(u,v,w);
        ed=u;
        
        spfa(st);
        printf("%d\n",(d[ed]!=0x3f3f3f3f)?d[ed]+e[1].w+e[cnt].w:-1);    
    }
}

 

posted @ 2019-04-22 18:50  羊肉汤泡煎饼  阅读(208)  评论(0编辑  收藏  举报