HDU 4411最小费用流

news/2024/11/26 4:36:06/

点击打开链接

题意:从0出发,1~N每个城镇有个小偷,我们要把他们全部抓到,我们可以派出k个警察,但是再抓i城镇的小偷之前,i城镇之前的所有城镇的小偷已经被抓了

思路:哪有什么思路,看了网上的题解,为了将所有的点都跑到,我们将每个点拆成两个点,之间连一条容量为1,费用为-1000000的边,为什么这么连,这是为了保证每个点的跑到的条件,因为最小费用流的增广路径是通过最短路来完成的,这样我的点拆成两个点之间的边加在最短路里肯定是会使路径更短的,这样也就保证了每个点都跑得到,现在说一说建边的方法,建立源点与0连一条容量为k费用为0的边,拆的点i与i+n连一条容量为1,费用为-1000000的边,然后0与汇点建立一条容量为k费用为0的边,这又是为什么呢,据说这些警察可以不全部出动去抓小偷,那他们就直接走这条边就好了,还有我们需要求出两点之间的最短距离,用floyd即可,然后连I到J的边,容量为1,费用为i到j的最短路(I<J),这样在增广时才能保证是从0顺次走到N,最后最小费用流+n*1000000就是结果了,将费用补回来

#include <queue>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=310;
typedef pair<int,int> P;
struct edge{int to,cap,cost,rev;edge();edge(int a,int b,int c,int d){to=a,cap=b,cost=c,rev=d;};
};
vector<edge>G[maxn];
int h[maxn],dis[maxn],prevv[maxn],preve[maxn],V;
void add_edge(int st,int en,int cap,int cost){G[st].push_back(edge(en,cap,cost,G[en].size()));G[en].push_back(edge(st,0,-cost,G[st].size()-1));
}
int min_cost_flow(int st,int en,int f){int ans=0;memset(h,0,sizeof(h));while(f>0){priority_queue<P,vector<P>,greater<P> >que;memset(dis,inf,sizeof(dis));dis[st]=0;que.push(P(0,st));while(!que.empty()){P p=que.top();que.pop();int v=p.second;if(dis[v]<p.first) continue;for(unsigned int i=0;i<G[v].size();i++){edge &e=G[v][i];if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){dis[e.to]=dis[v]+e.cost+h[v]-h[e.to];prevv[e.to]=v;preve[e.to]=i;que.push(P(dis[e.to],e.to));}}}if(dis[en]==inf) return -1;for(int i=0;i<maxn;i++) h[i]+=dis[i];int d=f;for(int i=en;i!=st;i=prevv[i]){d=min(d,G[prevv[i]][preve[i]].cap);}f-=d;ans+=d*h[en];for(int i=en;i!=st;i=prevv[i]){edge &e=G[prevv[i]][preve[i]];e.cap-=d;G[i][e.rev].cap+=d;}}return ans;
}
int num[maxn][maxn];
void floyd(){for(int i=0;i<=V;i++){for(int j=0;j<=V;j++){for(int k=0;k<=V;k++)num[j][k]=min(num[j][k],num[j][i]+num[i][k]);}}
}
int main(){int m,k,a,b,c;while(scanf("%d%d%d",&V,&m,&k)!=-1){if(V==0&&m==0&&k==0) break;memset(num,inf,sizeof(num));for(int i=0;i<maxn;i++) G[i].clear();for(int i=0;i<m;i++){scanf("%d%d%d",&a,&b,&c);num[a][b]=num[b][a]=min(num[a][b],c);}floyd();add_edge(2*V+10,0,k,0);add_edge(0,2*V+11,k,0);for(int i=1;i<=V;i++){for(int j=i+1;j<=V;j++){add_edge(i+V,j,1,num[i][j]);}add_edge(0,i,1,num[0][i]);add_edge(i,i+V,1,-1000000);add_edge(i+V,2*V+11,1,num[0][i]);}int ans=min_cost_flow(2*V+10,2*V+11,k);printf("%d\n",ans+V*1000000);}return 0;
}


http://www.ppmy.cn/news/370607.html

相关文章

hdu4411(费用流)

链接&#xff1a;点击打开链接 题意&#xff1a;给n1个点&#xff0c;m条边的无向图。起点为0&#xff0c;k个人初始在起点&#xff0c;去遍历图使得每个点至少被一人走过并且遍历i点时i-1必须已经被遍历&#xff0c;最后k人要回到起点。输出k个人最小的路径和 代码&#xff…

hdu4411 Arrest(费用流)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid4411 【题意】给定N1个点&#xff0c;距离&#xff0c;K个人&#xff0c;问&#xff0c;每人从0开始按照升序访问节点然后回到0&#xff0c;每个节点被访问一次的最小距离和。 【分析】费用流问题&#xff0c;因…

P4411BZOJ1978 [BJWC2010]取数游戏(动态规划dp)

P4411 一道dp f[i]表示一定选第i个数的条件下前i个数所能得到的最优值 last[i]表示质因数i在数列a中最后出现时的下标 状态转移方程为\(f[i]max\{f[last[j]\:|\: j|i \}1\) 复杂度\(O(n\sqrt{a_i})\) #include <bits/stdc.h> using namespace std; int n,l,ans,a[50005],…

ubuntu4411

http://bothlog.com/index.php/2010/08/resolve-ubuntu-10-04-ait-card-can-not-adjust-brightness-by-fn-key/

bzoj4411 [Usaco2016 Feb]Load balancing

http://www.elijahqi.win/archives/3059 Description 给出N个平面上的点。保证每一个点的坐标都是正奇数。 你要在平面上画两条线&#xff0c;一条是xa&#xff0c;一条是yb&#xff0c;且a和b都是偶数。 直线将平面划成4个部分&#xff0c;要求包含点数最多的那个部分点数…

HDU 4411 Arrest

分析&#xff1a;很明显的费用流&#xff0c;最重要的还是建图&#xff0c;首先确立源点和汇点&#xff0c;因为城市0为初始点&#xff0c;所以我定义s为源点&#xff0c;然后t为汇点&#xff0c;s-->0建边&#xff0c;流量为k&#xff0c;费用为0&#xff0c;因为不一定所有…

惠普电脑为什么打不开计算机刷题,如果无法打开HP笔记本计算机的无线开关该怎么办?惠普ProBook 4411s...

clp615808 通过 尊敬的HP用户&#xff0c;您好&#xff01;感谢您选择惠普产品. 根据您的描述&#xff0c;建议您参考以下信息: 1. 建议进入操作系统的桌面. 您可以右键单击[计算机](或[我的计算机])图标&#xff0c;选择[管理]&#xff0c;然后在页面左侧的[设备管理器]中-右键…

题解 P4411 【[BJWC2010]取数游戏】

看到大家都是用 f i f_i fi​ 来存储枚举到 i i i 的答案&#xff0c;这里再来一种别样的方法。 同样得先枚举 a i a_i ai​ 的约数&#xff0c;我们其实不需要存储 a i a_i ai​ , 边读边算即可。 我们用 m a i ma_i mai​ 存储约数为 i i i 的最大答案数量&#xff0…