zoukankan      html  css  js  c++  java
  • 【bzoj1877】[SDOI2009]晨跑 费用流

    题目描述

    Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑。 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校,保证寝室编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以 在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路 口。Elaxia耐力不太好,他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天 数尽量长。 除了练空手道,Elaxia其他时间都花在了学习和找MM上面,所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。

    输入

    第一行:两个数N,M。表示十字路口数和街道数。 接下来M行,每行3个数a,b,c,表示路口a和路口b之间有条长度为c的街道(单向)。

    输出

    两个数,第一个数为最长周期的天数,第二个数为满足最长天数的条件下最短的路程长 度。

    样例输入

    7 10
    1 2 1
    1 3 1
    2 4 1
    3 4 1
    4 5 1
    4 6 1
    2 5 5
    3 6 6
    5 7 1
    6 7 1

    样例输出

    2 11


    题解

    拆点+网络流费用流

    由于除源点汇点以外每个点只能经过一次,所以可以把每个点拆成两个,它们之间的路径容量为1。

    然后跑费用流即可。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define inf 0x7fffffff
    using namespace std;
    queue<int> q;
    int head[410] , to[50000] , val[50000] , cost[50000] , next[50000] , cnt = 1 , dis[410] , from[410] , pre[410] , s , t , f , c;
    void add(int x , int y , int z , int c)
    {
    	to[++cnt] = y;
    	val[cnt] = z;
    	cost[cnt] = c;
    	next[cnt] = head[x];
    	head[x] = cnt;
    }
    bool spfa()
    {
    	int i , x;
    	memset(from , -1 , sizeof(from));
    	memset(dis , 0x3f , sizeof(dis));
    	dis[s] = 0;
    	q.push(s);
    	while(!q.empty())
    	{
    		x = q.front();
    		q.pop();
    		for(i = head[x] ; i ; i = next[i])
    		{
    			if(val[i] && dis[to[i]] > dis[x] + cost[i])
    			{
    				dis[to[i]] = dis[x] + cost[i];
    				from[to[i]] = x;
    				pre[to[i]] = i;
    				q.push(to[i]);
    			}
    		}
    	}
    	return from[t] != -1;
    }
    void mincost()
    {
    	int i , k;
    	while(spfa())
    	{
    		k = inf;
    		for(i = t ; i != s ; i = from[i])
    			k = min(k , val[pre[i]]);
    		f += k;
    		c += k * dis[t];
    		for(i = t ; i != s ; i = from[i])
    			val[pre[i]] -= k , val[pre[i] ^ 1] += k;
    	}
    }
    int main()
    {
    	int n , m , i , x , y , z;
    	scanf("%d%d" , &n , &m);
    	s = 1 , t = n;
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		scanf("%d%d%d" , &x , &y , &z);
    		if(y != n) add(x , y + n , 1 , z) , add(y + n , x , 0 , -z);
    		else add(x , n , 1 , z) , add(y , x , 0 , -z);
    	}
    	for(i = 2 ; i <= n - 1 ; i ++ )
    		add(i + n , i , 1 , 0) , add(i , i + n , 0 , 0);
    	mincost();
    	printf("%d %d
    " , f , c);
    	return 0;
    }

     

  • 相关阅读:
    FFmpegTool 这个是很早以前写得ffmpeg c99部分转C89工具代码
    mmsplayer V2 for IOS 完成. V2 所有汇总
    关于mmsplayer一些电台不支持播放问题说明
    libmpg123 解码库用法
    [置顶] mmsplayer V2 for IOS 完成. V2 所有汇总
    使用lipo合并iPhone模拟器和真机的静态类库
    vbs编程
    Adobe reader查阅PDF文件无法显示中文
    常去的下载网站
    .Net程序设计快速入门——分页设计篇
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6490366.html
Copyright © 2011-2022 走看看