教皇与僭称教皇

来源:互联网 发布:mac ppt设置默认字体 编辑:程序博客网 时间:2024/04/29 22:56

题目描述 Problem Description

题目描述只是借了历史的名义而已,纯属虚构娱乐,我亵渎历史我有罪。

稳固了后方之后, 光下巴开始寻求加冕为神圣罗马帝国皇帝, 1153 年发动了第一次远征意大利。在进军途中,他接到了教皇尤金三世的求救信,原来是教士阿诺德领导人民夺取了城市政权,选举了罗马元老院成员和执政官,主张教会放弃领地过使徒的简朴生活。这真是天赐的机会, 金天成加速进军镇压了这次起义,以拯救者的身份进入罗马城。但新任教皇哈德良四世是个不懂变通的倔老头,他在为金天成加冕时,坚持要金天成按照惯例为教皇牵马、扶镫,激怒了金天成, 结果使庆典会场变成了战场,近千人被杀。但不管过程如何狼狈, 金天成已通过加冕获得了“神圣罗马帝国皇帝”的称号(在他之前的德皇,一直只称为“罗马帝国皇帝”,从他开始又冠上“神圣”二字)。好吧,现在出题人要管管这不知道如何狼狈过程了, 教堂的区域很少,只有 N 块区域。然后某些区域之间有通路。 这 N 块区域中每块区域都有敌军, N 个区域之间有 M 条通道。金天成大帝现在需要以闪电般的速度将这 N 个区域中敌军迅速歼灭。金天成大帝的军队比教皇军队要强很多,他们到达某个区域就能瞬间歼灭该区域的军队。 但是走第 i 条通道花的时间为 Ti 。由于某种特殊的作者编造不出来的原因导致金天成大帝不能回到以前曾经过的区域,所以金天成大帝希望有一种方案,使得他能最快歼灭教皇的军队,如果不存在方案,则输出 1 。 一开始金天成大帝所在区域为 1 号区域。


输入描述 Input Description

第一行两个数字 NM
接下来 M 行,每行三个数字 A,B,C,表示 AB 有一条通路,耗时为 C


输出描述 Output Description

输出一行,一个数字,表示金天成大帝干掉教皇军队的最少时间。


样例输入 Sample Input

5 4
1 2 3
2 3 4
3 4 5
4 5 6


输出样例 Sample Output

18


提示 Hint

1 开始一条路走到黑就 OK。


数据范围 Data Size

30% 的数据: 1N81M28
100% 的数据:1N161M1201C108


分析 I Think

注意到这里的 N 很小,可以采用状态压缩,设 disi,j 表示从 1 走到 i 时且状态为 j 的最短时间,其中 j 是一个二进制串,剩下求 disi,j 直接 spfa 乱搞就可以了。


代码 Code

#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;struct node{int x,y;node(int X=0,int Y=0){x=X;y=Y;}};int head[20],nxt[247],to[247],wei[247],tot;int dis[20][1<<17];bool vis[20][1<<17];queue<node>que;int n,m;void add(int,int,int);void spfa();int main(){    memset(head,-1,sizeof head);    memset(dis,0x3f,sizeof dis);    scanf("%d%d",&n,&m);    for(int i=1,x,y,z;i<=m;++i){        scanf("%d%d%d",&x,&y,&z);        --x;--y;        add(x,y,z);    }    spfa();    int r = (1<<n)-1;    int ans = 0x3f3f3f3f;    for(int i=1;i<n;++i)        ans = min(ans,dis[i][r]);    if(ans != 0x3f3f3f3f)        printf("%d",ans);    else        printf("-1");    return 0;}void add(int from,int tp,int weight){    ++tot;nxt[tot]=head[from];head[from]=tot;to[tot]=tp;wei[tot]=weight;    ++tot;nxt[tot]=head[tp];head[tp]=tot;to[tot]=from;wei[tot]=weight;}void spfa(){    que.push(node(0,1));    dis[0][1] = 0;    node now;    do{        now = que.front();        vis[now.x][now.y] = false;        que.pop();        for(int i=head[now.x];i;i=nxt[i])            if(!(now.y&(1<<to[i])) && dis[now.x][now.y]+wei[i]<dis[to[i]][now.y|(1<<to[i])]){                dis[to[i]][now.y|(1<<to[i])] = dis[now.x][now.y]+wei[i];                if(!vis[to[i]][now.y|(1<<to[i])]){                    vis[to[i]][now.y|(1<<to[i])] = true;                    que.push(node(to[i],now.y|(1<<to[i])));                }            }    }while(!que.empty());}
0 0