zoukankan      html  css  js  c++  java
  • BZOJ2324: [ZJOI2011]营救皮卡丘

    2324: [ZJOI2011]营救皮卡丘

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 1359  Solved: 522
    [Submit][Status]

    Description

    皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路。

    火箭队一共有N个据点,据点之间存在M条双向道路。据点分别从1N标号。小智一行K人从真新镇出发,营救被困在N号据点的皮卡丘。为了方便起见,我们将真新镇视为0号据点,一开始K个人都在0号点。

    由于火箭队的重重布防,要想摧毁K号据点,必须按照顺序先摧毁1K-1号据点,并且,如果K-1号据点没有被摧毁,由于防御的连锁性,小智一行任何一个人进入据点K,都会被发现,并产生严重后果。因此,在K-1号据点被摧毁之前,任何人是不能够经过K号据点的。

    为了简化问题,我们忽略战斗环节,小智一行任何一个人经过K号据点即认为K号据点被摧毁。被摧毁的据点依然是可以被经过的。

    K个人是可以分头行动的,只要有任何一个人在K-1号据点被摧毁之后,经过K号据点,K号据点就被摧毁了。显然的,只要N号据点被摧毁,皮卡丘就得救了。

    野外的道路是不安全的,因此小智一行希望在摧毁N号据点救出皮卡丘的同时,使得K个人所经过的道路的长度总和最少。

    请你帮助小智设计一个最佳的营救方案吧!

     

    Input

    第一行包含三个正整数N,M,K。表示一共有N+1个据点,分别从0N编号,以及M条无向边。一开始小智一行共K个人均位于0号点。 

    接下来M行,每行三个非负整数,第i行的整数为Ai,Bi,Li。表示存在一条从Ai号据点到Bi号据点的长度为Li的道路。

    Output

    仅包含一个整数S,为营救皮卡丘所需要经过的最小的道路总和。

    Sample Input


    3 4 2

    0 1 1

    1 2 1

    2 3 100

    0 3 1


    Sample Output

    3

    【样例说明】

    小智和小霞一起前去营救皮卡丘。在最优方案中,小智先从真新镇前往1号点,接着前往2号据点。当小智成功摧毁2号据点之后,小霞从真新镇出发直接前往3号据点,救出皮卡丘。

    HINT



    对于10%的数据满足 K = 1,且N = 3,小智将独自前去营救皮卡丘;


    对于20%的数据满足 K ≤ 3,且N ≤ 20,被小智单挑剿灭的火箭队加强了防御,增加了据点数;


    对于40%的数据满足 K ≤ 3,且N ≤ 100,面对加强的防御,小智拉来了好朋友小霞和小刚,一同前去营救;


    对于另外20%的数据满足任意一对据点之间均存在道路,并且对任意的0 ≤ X,Y,Z ≤ N,有不等式L(X,Z) ≤ L(X,Y) + L(Y,Z)成立;


    对于100%的数据满足N ≤ 150, M ≤ 20 000, 1 ≤ K ≤ 10, Li ≤ 10 000, 保证小智一行一定能够救出皮卡丘。


    至于为什么K ≤ 10,你可以认为最终在小智的号召下,小智,小霞,小刚,小建,小遥,小胜,小光,艾莉丝,天桐,还有去日本旅游的黑猫警长,一同前去大战火箭队。

    Source

    Day2

    题解:

    这题和星际竞速还有打印机两题的主体思路都是一样的

    每个点一定要经过,并且要经过这个点,必须经过比这个点小的所有点。而且还存在一个附加源,但源到附加源有一定的容量限制(星际没有。。。)

    这题我们采用如下方式建图:

    1.把每个点拆成 i 和 i+n 两个点,分别表示从这个点出发和进入这个点

    2.由s向所有i 连容量为1,费用为0的边

    2.由所有i+n到t连容量为1,费用为0的边

    3.由 i 向所有 j+n(j>n)连容量为1,费用为从 i 到 j,不经过比j标号大的中间节点的最短路 的边 (否则这条道路将不合法)

    正确性可以从i+n 入流的来源来考虑,每一种流法都代表着一种实实在在的、合法的方案,cost就是花费时间,我们要时间最短,自然要最小费用最大流了

    还有一个问题就是   

    费用为从 i 到 j,不经过比j标号大的中间节点的最短路  怎么求?

    我自己yy了一种想法,如下:

        for(int k=0;k<=n;k++)
         for(int i=0;i<=n;i++)
          for(int j=k;j<=n;j++)
           f[i][j]=min(f[i][j],f[i][k]+f[k][j]);

    意思就是不使用比 j 大的节点作为中间节点来更新 i(1..n)到j的最短路

    所以这个过程结束后,f[i][j]就代表着从 i 到 j不经过比 j大的节点的最短路

    代码:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<iostream>
     7 #include<vector>
     8 #include<map>
     9 #include<set>
    10 #include<queue>
    11 #define inf 1000000000
    12 #define maxn 500
    13 #define maxm 100000
    14 #define eps 1e-10
    15 #define ll long long
    16 #define pa pair<int,int>
    17 using namespace std;
    18 inline int read()
    19 {
    20     int x=0,f=1;char ch=getchar();
    21     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    22     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
    23     return x*f;
    24 }
    25 int n,m,k,tot=1,s,t,ss,head[maxn],q[maxn],from[maxn],f[maxn][maxn];
    26 bool v[maxn];
    27 ll d[maxn],mincost;
    28 struct edge{int from,next,go,v,c;}e[2*maxm];
    29 void ins(int x,int y,int z,int w)
    30 {
    31     e[++tot].go=y;e[tot].from=x;e[tot].v=z;e[tot].c=w;e[tot].next=head[x];head[x]=tot;
    32 }
    33 void insert(int x,int y,int z,int w)
    34 {
    35     ins(x,y,z,w);ins(y,x,0,-w);
    36 }
    37 bool spfa()
    38 {
    39     for (int i=s;i<=ss;i++)d[i]=inf;
    40     memset(v,0,sizeof(v));
    41     int l=0,r=1,y;q[1]=s;d[s]=0;v[0]=1;
    42     while(l!=r)
    43     {
    44         int x=q[++l];if(l==maxn)l=0;v[x]=0;
    45         for (int i=head[x];i;i=e[i].next)
    46          if(e[i].v&&d[x]+e[i].c<d[y=e[i].go])
    47          {
    48             d[y]=d[x]+e[i].c;from[y]=i;
    49             if(!v[y]){v[y]=1;q[++r]=y;if(r==maxn)r=0;}
    50          }
    51     }
    52     return d[t]!=inf;
    53 }
    54 void mcf()
    55 {
    56     while(spfa())
    57     {
    58         int tmp=inf;
    59         for(int i=from[t];i;i=from[e[i].from]) tmp=min(tmp,e[i].v);
    60         mincost+=d[t]*tmp;
    61         for(int i=from[t];i;i=from[e[i].from]){e[i].v-=tmp;e[i^1].v+=tmp;}
    62     }
    63 }
    64 int main()
    65 {
    66     freopen("input.txt","r",stdin);
    67     freopen("output.txt","w",stdout);
    68     n=read();m=read();k=read();
    69     memset(f,60,sizeof(f));
    70     for(int i=1;i<=m;i++)
    71     {
    72         int x=read(),y=read(),z=read();
    73         f[x][y]=min(f[x][y],z);f[y][x]=min(f[y][x],z);
    74     }
    75     s=0;t=2*n+1;ss=2*n+2;insert(s,ss,k,0);
    76     for(int k=0;k<=n;k++)
    77      for(int i=0;i<=n;i++)
    78       for(int j=k;j<=n;j++)
    79        f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
    80     for(int i=1;i<=n;i++)insert(s,i,1,0);
    81     for(int i=1;i<=n;i++)insert(ss,i+n,1,f[0][i]);
    82     for(int i=1;i<=n;i++)insert(i+n,t,1,0);
    83     for(int i=1;i<=n;i++)
    84      for(int j=i+1;j<=n;j++)
    85       insert(i,j+n,1,f[i][j]);
    86     mcf();
    87     printf("%lld
    ",mincost);     
    88     return 0;
    89 }
    View Code
  • 相关阅读:
    .Proto 文件转换成.cs文件
    C# 委托和事件
    C# 对word (03、07)的相关操作
    程序中记录日志的封装类
    压缩文件程.ZIP
    xml和对象直接的序列化和反序列化
    C#判断两个日期是否在同一周,某日期是本月的第几周
    vs2008 C# 单元测试
    解压缩.zip文件
    记录一次曲折的维护-重构过程
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/3931428.html
Copyright © 2011-2022 走看看