BZOJ2324: [ZJOI2011]营救皮卡丘

Posted mt-li

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2324: [ZJOI2011]营救皮卡丘相关的知识,希望对你有一定的参考价值。

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

 

对于100%的数据满足N ≤ 150, M ≤ 20 000, 1 ≤ K ≤ 10, Li ≤ 10 000, 保证小智一行一定能够救出皮卡丘。至于为什么K ≤ 10,你可以认为最终在小智的号召下,小智,小霞,小刚,小建,小遥,小胜,小光,艾莉丝,天桐,还有去日本旅游的黑猫警长,一同前去大战火箭队。

 

题目传送门

 

做完这道题我都有点迷糊,神tm我网络流什么时候做了将近40道了。。。

不会做啊,去%了发题解

首先floyd一遍每个点对的最小距离,控制一下前面的点对都被访问过,这里有个正确性我不会证

先给建图在解释:

1.S->0’ 流量K费用0

2.i’->j 流量1费用dis[i][j]

3.S->i’ 流量1费用0

4.i->T 流量1费用0

第一条和第二条我不讲了,这都不会左转天台

这道题我们要保证访问的每一个点都要被炸掉,所以这大概就叫有下界无上界

感觉还是有点不懂,先挖个坑吧

 

代码如下:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node
{
    int x,y,next,other;
    ll c,d;
}a[2100000];int len,last[2100000];
int INF=1<<29;

void ins(int x,int y,ll c,ll d)
{
    int k1,k2;
    k1=++len;
    a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
    a[len].next=last[x];last[x]=len;
    
    k2=++len;
    a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
    a[len].next=last[y];last[y]=len;
    
    a[k1].other=k2;
    a[k2].other=k1;
}
bool v[210000];
ll ans;
int st,ed,head,tail,pre[210000];
ll cc[210000],list[210000],d[210000];
bool SPFA()
{
    for(int i=0;i<=ed;i++)d[i]=INF;
    d[st]=0;
    memset(v,false,sizeof(v));v[st]=true;
    memset(cc,0,sizeof(cc));cc[st]=INF;
    list[1]=st;head=1;tail=2;
    while(head!=tail)
    {
        int x=list[head];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(a[k].c>0&&d[y]>d[x]+a[k].d)
            {
                d[y]=d[x]+a[k].d;
                pre[y]=k;
                cc[y]=min(cc[x],a[k].c);
                if(!v[y])
                {
                    v[y]=true;
                    list[tail++]=y;
                }
            }
        }
        head++;
        v[x]=false;
    }
    if(d[ed]==INF)return false;
    ans+=d[ed]*cc[ed];
    int x=ed;
    while(x!=0)
    {
        int k=pre[x];
        a[k].c-=cc[ed];a[a[k].other].c+=cc[ed];
        x=a[k].x;
    }
    return true;
}
int dd[210][210];
int n,m,K;
int main()
{
    scanf("%d%d%d",&n,&m,&K);st=n*2+2;ed=n*2+3;
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=n;i++)dd[i][i]=0;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            if(i!=j)
                dd[i][j]=INF;
    for(int i=1;i<=m;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        dd[x][y]=dd[y][x]=min(dd[x][y],c);
    }
    
    for(int k=0;k<=n;k++)
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                if(k<=i||k<=j)
                    dd[i][j]=min(dd[i][j],dd[i][k]+dd[k][j]);
                    
    for(int i=1;i<=n;i++)
    {
        ins(st,i+n+1,1,0);
        ins(i,ed,1,0);
    }
    ins(st,n+1,K,0);
    for(int i=0;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if(dd[i][j]!=INF)
                ins(i+n+1,j,1,dd[i][j]);
    ans=0;
    while(SPFA()==true){}
    printf("%lld\n",ans);            
    return 0;
}

by_lmy

以上是关于BZOJ2324: [ZJOI2011]营救皮卡丘的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2324 [ZJOI2011]营救皮卡丘

BZOJ2324[ZJOI2011]营救皮卡丘 有上下界费用流

BZOJ2324: [ZJOI2011]营救皮卡丘

BZOJ 2324[ZJOI2011]营救皮卡丘 费用流

BZOJ2324 [ZJOI2011]营救皮卡丘 费用流

bzoj2324 [ZJOI2011]营救皮卡丘