洛谷 U78696 图书馆馆长的考验 题解

题面

1. 图书馆馆长的考验(library)

红魔馆的拥有者蕾米莉亚的好友帕秋莉是红魔馆的大图书馆的馆长。擅长操纵五行,名言是“万物都有属性。所谓的属性,和弱点是一样的”。

一天,因为魔理沙看了神之右大臣的视频却不投硬币不点收藏不加关注导致受到了幽幽子的追杀。在博丽灵梦的引荐下,魔理沙来到红魔馆去向帕秋莉学习暗黑魔法来打败幽幽子

   但帕秋莉不想这么轻易的教她,所以身为图书馆馆长的她发动了禁术,改变了图书馆的结构,让其变为了一个巨大的迷宫。这个迷宫一共有n个房间,m条通道。开始时魔理沙在1号房间,帕秋莉在n号房间。有的房间之间存在一个通道(双向),表示可以从ui号房间到达vi号房间(反过来也可以)。如果想通过该通道,魔理沙就需要使用一个消耗魔法值为wi的魔法来抵抗该通道的攻击。

   为了能够提高魔理沙到达n号房间的可能性,帕秋莉将改变后的图书馆地图发送给了魔理沙。

   魔理沙懒得不像样,直接把地图递给了你,让你告诉她如何前进才能到达。(任意一条路线都可以)。

   这太简单了!身为AK noip的你一看就已经知道了一条路径,但魔理沙接下来又说,“既然看都看了,就直接告诉我到那最轻松(消耗魔法值最少)的路吧 DAZE

   那也很简单啊!你刚打算说答案,帕秋莉的声音从你的脑中响起:“原来的图书馆中含有p个暗道,如今这些暗道依然存在。这些暗道在地图上没有体现,现在告诉你,这或许会影响你的答案。但如果要走从a到b的暗道(双向),不仅要消耗ti的魔法值来维持传送,而且一定要到c房间去读一本书(不消耗魔法值)来找到打开这个暗道的机关,不同暗道所需读的书不同且可能不在同一房间。”

这还是很简单啊!!!你经过少许计算后得出了结果,告诉了魔理沙

为了简便,你只告诉她该方案所消耗的魔法值(答案在int范围内)。

输入格式:

   第一行输入n,m,p;

   接下来m行每行格式为ui,vi,wi;

   接下来p行每行输入ci,ai,bi,ti;

输出格式:

   输出一行:消耗魔法值最少的路所消耗的魔法值。

数据范围:

   对于10%的数据,n<=300,m<=500且p=0。

对于另20%的数据,仅保证p=0;

对于另20%的数据,保证n<=300,m<=500,且该图是一棵树;wi>0,ti>0

对于100%的数据,n<=1000,m<=2000,p<=10;(普遍情况下n比m要小得多)

输入样例1

10 9 0

1 2 2

2 3 29

3 4 3

4 5 124

5 6 123

6 7 45

7 8 21

8 9 211

9 10 48

 

输出样例1

606

 

 

输入样例2

 

10  11  1

 

1  2  213

 

2  3  134

 

2  4  112

 

4  3  113

 

3  9  145

 

9  5  311

 

4  5  421

 

4  6  112

 

6  7  341

 

7  8  121

 

8  10  461

 

4  9  10  121

 

 

 

输出样例2

 

704

 


题解:

#include <iostream>
#include <cstdio>
#pragma GCC optimize(2)
using namespace std;
int n,m,p;
struct littlestar{
    int to;
    int nxt;
    int w;
}star[10300000];
int head[10300000],cnt;
void add(int u,int v,int w)
{
    star[++cnt].to=v;
    star[cnt].w=w;
    star[cnt].nxt=head[u];
    head[u]=cnt;
}
int floor,tot;
int have[20];
int ans=999999999;
int dis[10300000],vis[10300000],q[10300000];
void spfa()
{
    for(register int i=1;i<=tot;i++)
    {
        dis[i]=999999999;
    }
    dis[1]=0;
    vis[1]=1;
    int h=1,t=1;
    q[1]=1;
    while(h<=t){
        int u=q[h];
        for(register int j=head[u];j;j=star[j].nxt){
            int v=star[j].to;
            if(dis[v]>dis[u]+star[j].w){
                dis[v]=dis[u]+star[j].w;
                if(!vis[v]){
                    q[++t]=v;
                    vis[v]=1;
                }
            }
        }
        vis[u]=0;
        ++h;
    }
}
int main ()
{    
    //freopen("library.in","r",stdin);
    cin>>n>>m>>p;
    floor=1<<p;    
    tot=n*floor;
    for(register int i=1;i<=m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        for(register int j=0;j<floor;j++){
            add(n*j+x,n*j+y,z);
            add(n*j+y,n*j+x,z);
        }    
    }        
    for(register int k=1;k<=p;k++){
        int x,u,v,w;
        scanf("%d%d%d%d",&x,&u,&v,&w);
        for(register int i=0;i<floor;i++){
            for(register int j=1;j<=p;j++){
                if(i&(1<<(j-1))){
                    have[j]=1;
                }
                 else have[j]=0;
            }
            if(have[k]==1){
                add(n*i+u,n*i+v,w);
                add(n*i+v,n*i+u,w);
            }
            int tmp=i^(1<<(k-1));
            add(n*tmp+x,n*i+x,0);
         }
    }
    spfa();
    for(register int i=0;i<floor;i++){
        ans=min(ans,dis[i*n+n]);
    }
    cout<<ans<<endl;
}
/*
10 11 1
1 2 213
2 3 134
2 4 112
4 3 113
3 9 145
9 5 311
4 5 421
4 6 112
6 7 341
7 8 121
8 10 461
4 9 10 121


10 9 0
1 2 2 
2 3 29
3 4 3
4 5 124
5 6 123
6 7 45
7 8 21
8 9 211
9 10 48
*/

文本框: 输入样例1:
10 9 0
1 2 2
2 3 29
3 4 3
4 5 124
5 6 123
6 7 45
7 8 21
8 9 211
9 10 48

输出样例1:
606

猜你喜欢

转载自www.cnblogs.com/kamimxr/p/11281027.html