(同时也是HDU 2982,UVA的数据多)

题意:平面上有m条有向线段连接了n个点。你从某个点出发顺着有向线段行走,给走过的每条线段涂一种不同的颜色,最后回到起点。你可以多次行走,给多个回路涂色(要么不涂色,要么就至少给一个回路上的边全部涂色)。可以重复经过一个点,但不能重复经过一条有向线段。如下图所示的是一种涂色方法(虚线表示未涂色,即每次都可以从任意点出发染色)。每涂一个单位长度将得到X分,但每使用一种颜色将扣掉Y分。假设你拥有无限多种的颜色,问如何涂色才能使得分最大?输入保证若存在有向线段u -> v,则不会出现有向线段v -> u。

  n <= 100,m <= 500,1 <= X,Y <= 1000。

  对于坐标(x,y)0 <= x,y <= 1000。

思路:看刘汝佳的书的第二种方法,再参考这篇博文才把代码长度降下来了。http://blog.csdn.net/u013368721/article/details/30553815
要求的就是 最大费用循环流(即每找到一个环就可以进行增广)。找环可能并不复杂,但是要找一个最大的环就有点复杂了,所以用网络流解决。又因为找的是最大费用,按老套路的话会出现无限增大费用的情况,所以要先将每条边的费用取相反数(前面加个负),才可以有机会求最小费用流。而这些边的权有正有负,取完之后也可能出现负环了,所以主要问题就是解决负环。
用 最小费用流求 最大费用循环流时,解决负环的一种方法:
(1)先将所有边权取反。
(2)建边。正权值的边容量为1,费用为权值。负权值的边u->v拆成3条边,分别是S->v,v->u,u->T,容量都为1,v->u费用为负权的相反数,其他2条费用为0。这样会出现某个点有多条边连到S或T,可以互相抵消到一方为0为止,统计剩下多少条k,将其中1条的容量设为k,其他的全部删掉。如果全部抵消掉了,那就将连S和T的边全部删掉。(这个删边的方法有技巧)
(3)跑一次最小费用流得到的总费用,加上所有负权之和之后(注:此时答案已为负的),再取反即得到最大费用。
删边技巧是,在建这S->v,v->u,u->T 三条边时,先建中间那条,统计该点连到S几次,减去连到T点几次,结果若为正,则与S连一条边,容量就是几次,若负,同理。
至于why it works!得好好想想~
画几个点验证了一下发现,如果一个原图中的环(权值大于0)值得取,那么流会自动流向该环原图中的负权边。而如果不值得取,那么会流向原图中的正权边。因为我们是用sum(负值)加上那个费用(正值),所以当该环要取时,则自动减去那些负权,不取呢,会自动减去那些正权(而那些负权的完全没取到)。不懂就画个环出来验证吧。

  1 #include <bits/stdc++.h>
  2 #define LL long long
  3 #define pii pair<int,int>
  4 #define pdi pair<double,int>
  5 #define INF 0x7f7f7f7f
  6 using namespace std;
  7 const int N=200;
  8 int x[N], y[N], rudu[N];
  9 int earn, lost, n;
 10 vector<int> vect[N], vec[N];
 11 double sum;
 12
 13 struct node
 14 {
 15     int from, to, cap, flow;
 16     double val;
 17     node(){};
 18     node(int from,int to,double val,int cap,int flow):from(from),to(to),val(val),cap(cap),flow(flow){};
 19 }edge[90000];
 20 int edge_cnt;
 21
 22 void add_node(int from,int to,double val,int cap,int flow)
 23 {
 24     edge[edge_cnt]=node(from, to, val, cap, flow );
 25     vec[from].push_back(edge_cnt++);
 26 }
 27
 28 void build_graph()
 29 {
 30     for(int i=1; i<=n; i++)
 31     {
 32         for(int j=0; j<vect[i].size(); j++)
 33         {
 34             int t=vect[i][j];
 35             double v= lost - sqrt( pow(x[i]-x[t],2)+pow(y[i]-y[t],2) )*earn;
 36
 37             if(v<0)
 38             {
 39                 add_node(t, i, -v, 1, 0 );  //反边
 40                 add_node(i, t, v, 0, 0 );
 41                 sum+=v;
 42                 rudu[t]++,rudu[i]--;
 43             }
 44             else
 45             {
 46                 add_node(i, t, v, 1, 0);
 47                 add_node(t, i, -v, 0, 0);
 48             }
 49         }
 50     }
 51     for(int i=1; i<=n; i++)
 52     {
 53         if(rudu[i]>0)
 54         {
 55             add_node(0, i, 0, rudu[i], 0);
 56             add_node(i, 0, 0, 0, 0);
 57         }
 58         if(rudu[i]<0)
 59         {
 60             add_node(i, n+1, 0, -rudu[i], 0);
 61             add_node(n+1, i, 0, 0, 0);
 62         }
 63     }
 64 }
 65
 66 int flow[N], path[N], inq[N];
 67 double cost[N];
 68
 69 double spfa(int s,int e)
 70 {
 71     deque<int> que(1,s);
 72     cost[s]=0;
 73     flow[s]=INF;
 74     inq[s]=1;
 75     while(!que.empty())
 76     {
 77         int x=que.front();
 78         que.pop_front();
 79         inq[x]=0;
 80         for(int i=0; i<vec[x].size(); i++)
 81         {
 82             node e=edge[vec[x][i]];
 83             if(e.cap>e.flow && cost[e.to]>cost[e.from]+e.val )
 84             {
 85                 flow[e.to]=min(flow[e.from],e.cap-e.flow);
 86                 cost[e.to]=cost[e.from]+e.val;
 87                 path[e.to]=vec[x][i];
 88                 if(!inq[e.to])
 89                 {
 90                     inq[e.to]=1;
 91                     que.push_back(e.to);
 92                 }
 93             }
 94         }
 95     }
 96     return cost[e];
 97 }
 98
 99 double mcmf(int s,int e)
100 {
101     double ans_cost=0.0;
102     while(true)
103     {
104         memset(flow,0,sizeof(flow));
105         memset(inq,0,sizeof(inq));
106         memset(path,0,sizeof(path));
107         for(int i=0; i<=e; i++)   cost[i]=1e39;
108
109         double tmp=spfa(s,e);    //返回费用
110         if(tmp>1e38)    return  ans_cost;
111         ans_cost+=tmp;
112
113         int ed=e;
114         while(ed!=s)
115         {
116             int t=path[ed];
117             edge[t].flow+=flow[n+1];
118             edge[t^1].flow-=flow[n+1];
119             ed=edge[t].from;
120         }
121     }
122 }
123
124 int main()
125 {
126     freopen("input.txt", "r", stdin);
127     int b, j=0;
128     while(scanf("%d", &n), n)
129     {
130         scanf("%d%d",&earn,&lost);
131         for(int i=0; i<=n+1; i++)   vect[i].clear();
132         for(int i=0; i<=n+1; i++)   vec[i].clear();
133         memset(edge,0,sizeof(edge));
134         memset(rudu,0,sizeof(rudu));
135         edge_cnt=0;
136         sum=0;
137
138         for(int i=1; i<=n; i++)
139         {
140             scanf("%d%d",&x[i],&y[i]);
141             while(scanf("%d",&b), b)    vect[i].push_back(b);   //原图邻接表
142         }
143         build_graph();
144         printf("Case %d: %.2f\n", ++j,  -(mcmf(0,n+1)+sum)+0.0000001 );
145     }
146     return 0;
147 }

AC代码

转载于:https://www.cnblogs.com/xcw0754/p/4659201.html

UVA 1659 Help Little Laura 帮助小劳拉 (最小费用流,最小循环流)相关推荐

  1. android手机小内存,世界最小Android手机问世 仅2.4英寸512MB内存

    如今的智能手机市场早已被大屏设备所占据,但苹果的iPhone SE证明了小尺寸手机依然有发展空间.可和最近发布的Posh Mobile Micro X S240相比,就连苹果这款手机也会显得巨大无比. ...

  2. OJ题目9--最小路径、最小消耗的动态规划问题

    一般来讲,涉及到最小路径的问题,目标都会有一个固定的行走模式,也就是说对于行走范围内的某一点而言,到达该点的各种可能性是确定了的(被确定了的行走模式所约束).那么走到一点的最小消耗,就等于所有差一步就 ...

  3. UVA 11419 SAM I AM(最大二分匹配最小点覆盖:König定理)

    题意:在方格图上打小怪,每次可以清除一整行或一整列的小怪,问最少的步数是多少,又应该在哪些位置操作(对输出顺序没有要求). 分析:最小覆盖问题 这是一种在方格图上建立的模型:令S集表示"行& ...

  4. python2 with open encoding_python with open as f写中文乱码

    python3和python2的写法不一样具体如下: python3: with open(r'd:\ssss.txt','w',encoding='utf-8') as f: f.write(u'中 ...

  5. 紫书《算法竞赛入门经典》

    紫书<算法竞赛入门经典>题目一览 第3章 数组和字符串(例题) UVA 272 TEX Quotes UVA 10082 WERTYU UVA 401 Palindromes UVA 34 ...

  6. wxWidgets:通过组合现有小部件制作新的可重用小部件

    wxWidgets:通过组合现有小部件制作新的可重用小部件 wxWidgets:通过组合现有小部件制作新的可重用小部件 wxWidgets:通过组合现有小部件制作新的可重用小部件 以下是如何通过组合现 ...

  7. android studio导出apk_Android 应用构建速度提升的十个小技巧

    应用的构建速度会直接影响开发效率,本文将带您通过改造一个 Android 应用: "Google 追踪圣诞老人 (Google Santa Tracker)" 来为大家提供十个小技 ...

  8. 配置高性能ElasticSearch集群的9个小贴士

    Loggly服务底层的很多核心功能都使用了ElasticSearch作为搜索引擎.就像Jon Gifford(译者注:Loggly博客作者之一)在他近期关于"ElasticSearch vs ...

  9. C#LeetCode刷题之#671-二叉树中第二小的节点(Second Minimum Node In a Binary Tree)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4100 访问. 给定一个非空特殊的二叉树,每个节点都是正数,并且每 ...

最新文章

  1. MySQL 优化上来就分库分表?面试官:根本不懂底层原理!
  2. PyTorch模块类
  3. 场景创新,推动金融行业数字化转型
  4. linux 查看opengl版本,linux下查看OpenGL版本
  5. 有关 Conversion to Dalvik format failed with error 1
  6. SQL Server 登录更换【Windows身份验证】为【SQL Server 身份验证】
  7. static和extern的用法总结
  8. python server酱_Python 超简单的邮件发送方法
  9. SQL:插入数据的小坑
  10. 【Oracle】lsnrctl reload 命令简介
  11. ERROR: The environment variable VG_GNU_PACKAGE must be set. Aborting.
  12. JavaScript 代码收集
  13. kotlin 使用viewStub
  14. ChromeOS+Win双系统安装教程
  15. win10修改用户名||user中文名改英文名
  16. 431 Request Header Fields Too Large
  17. 关于Mysql8.0时区表问题解决
  18. 习题 3.6 请编程序将China译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母。
  19. Q1成绩:华为可穿戴设备增幅亮眼,Uber亏损10亿美元!
  20. 自用PTA题目记录0024

热门文章

  1. 宫本茂的童心和乔布斯的叛逆--设计哲学背后的文化基因
  2. NetBSD 软件安装
  3. Excel多条件查找之lookup
  4. paper 11:matlab中fix函数,floor函数,ceil函数,round函数的区分
  5. vue两个卡片并排_Vue组件-卡片层叠拖拽
  6. js算法中的时间复杂度
  7. 领英创始人里德·霍夫曼退出OpenAI;微软推出多模态模型 Kosmos-1;谷歌推出PaLM-E...
  8. python接口测试—get请求
  9. 耿明雨传递正能量力争酱酒高品质
  10. fortran读写二进制文件