hdu 4067 #最小费用流
来源:互联网 发布:淘宝推广文案怎么写 编辑:程序博客网 时间:2024/06/05 14:37
题意是问是否能通过删除边后存在一个起点出度-入度为1,终点入度-出度为1,其余点出度==入度的图。
同时删边与留边都要话费,要求最后花费最少。
类似混合欧拉图
因为可以把每个点的度数看作要运送的物品。最后出度大的点连向原点,入度大的点连向汇点,//注意连的方向,不然要wa
关于最小值
默认都取操作最小值,即
如果删的费用大即留该条边,此时起点度数-- ,终点度数++,再添加一条从终点到起点,流量为1(/度数运输),费用为b-a的边,(可以在流动时允许删掉这条边,将终点的一个度数运输到起点,花费了b-a)。
如果留的费用打即删该条边,即不更新度数,建立一条从起点到终点,流量为1 , 费用为a-b的边。
当然也可以不这么建图,比如初始就是所有都留的数据,再都建b-a从终点到起点的边,但注意不要建重边,即没条边在途中只对应一条边。
ok , can you hear me ?
#include<iostream>#include<cstdio>#include<cstring>#include <queue>using namespace std;int n , m ;int deg[200] ;typedef long long ll ;#define type llconst int maxn = 2200 ;const int maxm = 200200 ;const int INF = 0x3f3f3f3f ;int s, t;struct node { int u, v, next; type cap, flow, cost;}edge[maxm];int head[maxn], cnt;int pre[maxn];type dis[maxn];bool vis[maxn];int N;void init () { memset (head, -1, sizeof head); cnt = 0;}void add_edge (int u, int v, type cap, type cost) { edge[cnt].u = u, edge[cnt].v = v, edge[cnt].cap = cap, edge[cnt].flow = 0; edge[cnt].cost = cost, edge[cnt].next = head[u], head[u] = cnt++; edge[cnt].u = v, edge[cnt].v = u, edge[cnt].cap = 0, edge[cnt].flow = 0; edge[cnt].cost = -cost, edge[cnt].next = head[v], head[v] = cnt++;}bool spfa (int s, int t) { queue <int> q; for (int i = 0; i < N; i++) { dis[i] = INF; vis[i] = 0; pre[i] = -1; } dis[s] = 0; vis[s] = 1; q.push (s); while (!q.empty ()) { int u = q.front (); q.pop (); vis[u] = 0; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if (edge[i].cap > edge[i].flow && dis[v] > dis[u]+edge[i].cost) { dis[v] = dis[u]+edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = 1; q.push (v); } } } } if (pre[t] == -1) return 0; else return 1;}int MCMF (int s, int t, type &cost) { type flow = 0; cost = 0; while (spfa (s, t)) { type Min = INF; for (int i = pre[t]; i != -1; i = pre[edge[i^1].v]) { if (Min > edge[i].cap-edge[i].flow) { Min = edge[i].cap-edge[i].flow; } } for (int i = pre[t]; i != -1; i = pre[edge[i^1].v]) { edge[i].flow += Min; edge[i^1].flow -= Min; cost += edge[i].cost*Min; } flow += Min; } return flow;}int main(){ int kase , tt = 1 ; scanf("%d" , &kase) ; int st , ed , u , v , a , b ; while( kase -- ){ scanf("%d %d %d %d" , &n , &m , &st , &ed ) ; init() ; N = n + 2 ; /// point actually memset( edge , 0 , sizeof( edge )) ; memset(deg , 0 , sizeof( deg )) ; ll ans = 0 ; for(int i = 0 ; i < m ; i ++ ){ scanf("%d %d %d %d" , &u , &v , &a , &b ) ; //add_edge(u , v , 1 , 0 ) ; if( a >= b ){ add_edge(u , v , 1 , a-b) ; ans += b ; } else if( a < b ){ add_edge(v , u , 1 , b-a) ; deg[u] -- , deg[v] ++ ; ans += a ; } } ll an = 0 ; deg[st] ++ ; deg[ed] -- ; int total_flow = 0 ; for(int i = 1 ; i <= n ; i ++ ){ if( deg[i] >= 0 ){ add_edge(0 , i , deg[i] , 0 ) ; total_flow += deg[i] ; }else if( deg[i] < 0 ){ add_edge(i , n+1 , -deg[i] , 0 ) ; } } int temp_flow = MCMF(0 , n+1 , an) ; //for( int i = 1 ; i <= n ; i ++ ) cout << deg[i] << " " ; cout << endl ; //cout << temp_flow << " " << total_flow << endl ; //cout << ans << " " << an << endl ; if( temp_flow == total_flow ) printf("Case %d: %lld\n" , tt ++ , an + ans) ; else printf("Case %d: impossible\n" , tt ++) ; } return 0 ;}
阅读全文
0 0
- hdu 4067 #最小费用流
- hdu 4067 最小费用最大流
- hdu 4067(最小费用最大流)
- hdu 4411(最小费用流)
- HDU 4411最小费用流
- HDU 3488 最小费用流
- HDU 4067(Random Maze) 最小费用流最大流
- hdu 4067 Random Maze(最小费用最大流)
- hdu 4067 Random Maze(最小费用最大流)
- HDU 4067 Random Maze 最小费用最大流
- hdu 4067 Random Maze(最小费用流)
- hdu 4067 Random Maze 最小费用最大流
- Random Maze - HDU 4067 最小费用最大流
- HDU 4067 Random Maze 最小费用最大流
- HDU 4067 Random Maze (最小费用最大流)
- 最小费用最大流 HDU 1533
- HDU 1853 最小费用最大流
- hdu 1853 最小费用最大流
- C++学习笔记,D2D加载本地图片并显示
- java集合之LinkList解析
- hdu1535 Invitation Cards(dijkstra+邻接表)(反向建图)
- HDU 2923-Einbahnstrasse(floyd&&字符串输入)
- 第二周 C/C++语言中函数参数函数传递的三种方式
- hdu 4067 #最小费用流
- oracle 数据库的基本操作(表空间、表、用户的创建及查询)
- ThreadLocal 和神奇的数字 0x61c88647
- EL表达式:字符串为空的判断
- 第二周项目2
- linux学习笔记(21)
- PopupWindow 详解
- 微信小程序开发 错误修改方法笔记
- 浅析VO、DTO、DO、PO的概念、区别和用处