• [CSP-S模拟测试]:壕游戏(费用流)


    题目传送门(内部题18)


    输入格式

    第一行包括四个数$n,m,k,s$表示有$n$个剧情点,$m$个关卡,要玩$k$次游戏,$s$个完结点接下来一行包含$s$个数,代表$s$个完结点的编号。
    接下来$m$行,每行五个正整数$x_i,y_i,A_i,B_i,C_i$,代表第$i$号关卡从$x_i$号剧情点连向$y_i$号剧情点,$A_i,B_i,C_i$意义如题目描述。


    输出格式

    如果不能通关输出$-1$,否则输出一个整数,代表至少需要的软妹币值。


    样例

    样例输入:

    6 8 2 2
    4 5
    1 2 4 0 2
    1 3 5 0 2
    3 4 1 5 1
    2 5 1 0 1
    4 6 4 2 2
    5 6 0 4 2
    1 5 5 9 2
    2 6 4 5 2

    样例输出:

    16


    数据范围与提示

    样例解释:

    第一次从$1−>2−>5$,费用为$5$。
    第二次从$1−>3−>4$,费用为$11$。

    数据范围:

    对于$30\%$的数据,$A_i=0$。
    对于另外$20\%$的数据,游戏为一条链。
    对于$100\%$的数据,$1leqslant nleqslant 1,000,1leqslant mleqslant 20,000,1leqslant kleqslant 200,A_i,B_igeqslant 0,1leqslant C_ileqslant k$。
    保证答案在$int$范围内。


    题解

    注意到$k$只有200,但是又有谁能想到是费用流呢?

    实际上,我的思路和题解稍有偏差。

    建边的时候记录上边的$A,B$,每走一次就让花费增加,退流的时候再剪掉就好了,缺点就是每次只能流一个,不然有可能会错过最优答案。

    时间复杂度:$Theta(m imes k+n imes k^2)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec
    {
    	int nxt;
    	int to;
    	int w;
    	int f;
    	int a;
    }e[100001];
    int head[5001],cnt=1;
    int n,m,k,s;
    int S,T;
    int que[100001],pre[50001],dis[50001];
    bool vis[50001];
    int ans;
    void add(int x,int y,int w,int f,int a)
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	e[cnt].w=w;
    	e[cnt].f=f;
    	e[cnt].a=a;
    	head[x]=cnt;
    }
    bool bfs()
    {
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	dis[S]=0;
    	vis[S]=1;
    	int he=1,ta=1;
    	que[ta]=S;
    	while(he<=ta)
    	{
    		for(int i=head[que[he]];i;i=e[i].nxt)
    			if(e[i].w&&dis[que[he]]+e[i].f<dis[e[i].to])
    			{
    				dis[e[i].to]=dis[que[he]]+e[i].f;
    				pre[e[i].to]=i;
    				if(!vis[e[i].to])
    				{
    					vis[e[i].to]=1;
    					que[++ta]=e[i].to;
    				}
    			}
    		vis[que[he]]=0;
    		he++;
    	}
    	return dis[T]!=1061109567;
    }
    void update()
    {
    	int flag=T;
    	while(flag!=S)
    	{
    		int x=pre[flag];
    		ans+=e[x].f;
    		e[x].w--;
    		e[x^1].w++;
    		e[x].f+=e[x].a;
    		e[x^1].f-=e[x].a;
    		flag=e[x^1].to;
    	}
    }
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&k,&s);
    	S=n+1,T=n+2;
    	add(S,1,k,0,0);
    	add(1,S,0,0,0);
    	for(int i=1;i<=s;i++)
    	{
    		int x;
    		scanf("%d",&x);
    		add(x,T,k,0,0);
    		add(T,x,0,0,0);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,a,b,c;
    		scanf("%d%d%d%d%d",&x,&y,&a,&b,&c);
    		add(x,y,c,b+a,a);
    		add(y,x,0,-b,a);
    	}
    	cnt=0;
    	while(bfs())
    	{
    		update();
    		cnt++;
    	}
    	if(cnt<k)puts("-1");
    	else printf("%d",ans);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    解决GOOGLE不能用的办法
    Elmah错误日志工具
    Linq 更改主键值
    qcow2、raw、vmdk等镜像格式
    Ceph相关博客、网站(256篇OpenStack博客)
    Delphi中inherited问题
    Qt qss一些伪装态,以及margin与padding区别
    Qt双缓冲机制:实现一个简单的绘图工具(纯代码实现)
    写出一篇好博文需要用到的工具
    最短路径启蒙题
  • 原文地址:https://www.cnblogs.com/wzc521/p/11447008.html
Copyright © 2020-2023  润新知