题目来源:
https://www.luogu.org/problemnew/show/P1344
题目描述:
题目描述
你第一天接手三鹿牛奶公司就发生了一件倒霉的事情:公司不小心发送了一批有三聚氰胺的牛奶。很不幸,你发现这件事的时候,有三聚氰胺的牛奶已经进入了送货网。这个送货网很大,而且关系复杂。你知道这批牛奶要发给哪个零售商,但是要把这批牛奶送到他手中有许多种途径。送货网由一些仓库和运输卡车组成,每辆卡车都在各自固定的两个仓库之间单向运输牛奶。在追查这些有三聚氰胺的牛奶的时候,有必要保证它不被送到零售商手里,所以必须使某些运输卡车停止运输,但是停止每辆卡车都会有一定的经济损失。你的任务是,在保证坏牛奶不送到零售商的前提下,制定出停止卡车运输的方案,使损失最小。
输入输出格式
输入格式:
第一行: 两个整数N(2<=N<=32)、M(0<=M<=1000), N表示仓库的数目,M表示运输卡车的数量。仓库1代 表发货工厂,仓库N代表有三聚氰胺的牛奶要发往的零售商。 第2..M+1行: 每行3个整数Si,Ei,Ci。其中Si,Ei表示这 辆卡车的出发仓库,目的仓库。Ci(0 <= C i <= 2,000,000) 表示让这辆卡车停止运输的损失。
输出格式:
两个整数C、T:C表示最小的损失,T表示在损失最小的前提下,最少要停止的卡车数。
输入输出样例
输入样例#1: 复制
4 5 1 3 100 3 2 50 2 4 60 1 2 40 2 3 80
输出样例#1: 复制
60 1
说明
题目翻译来自NOCOW。
USACO Training Section 4.4
解题思路:
这题的题意就是为了是1-n不联通,求最小割去的边权和,和割边数,首先我们知道最小割边应该是等于边权为一的最大流,所以我们只要求一遍最大流就行,但是由于有第二问,所以我们需要一个小技巧,就是把所有的边权都乘上一个大于边数的值mod,然后跑一遍最大流,ans/mod和ans%mod就是两个问题的值,为什么呢?我们假设原来答案,就是割边数是ans,显然ans=w1+w2+w3+w4+...=ans,现在就是(w1*mod+1)+(w2*mod+1)+(w3*mod+1)....+=ans*mod+k;所以可以知道把答案除mod和模mod就可以得到答案了。所以我们就跑一遍最大流,最大流代码都不会,是我太菜。。。。
代码:
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#define ll long long
using namespace std;
const ll N=100005,inf=233333333333333,mod=2018;
ll n,m,s,t,h[100],dis[2005],cnt=1;
ll ans;
struct edge{
ll to,net;ll v;
}e[N];
inline void add(ll u,ll v,ll w)
{
e[++cnt].to=v,e[cnt].net=h[u],e[cnt].v=w,h[u]=cnt;
e[++cnt].to=u,e[cnt].net=h[v],e[cnt].v=0,h[v]=cnt;
}
queue<ll>q;
inline bool bfs()
{
memset(dis,-1,sizeof(dis));
q.push(s),dis[s]=0;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=h[u];i;i=e[i].net)
if(dis[e[i].to]==-1&&e[i].v>0)dis[e[i].to]=dis[u]+1,q.push(e[i].to);
}
return dis[t]!=-1;
}
inline ll dfs(ll u,ll op)
{
if(u==t)return op;
ll flow=0,used=0;
for(int i=h[u];i;i=e[i].net)
{
int v=e[i].to;
if(dis[v]==dis[u]+1&&e[i].v>0)
{
used=dfs(v,min(op,e[i].v));
if(!used)continue;
flow+=used,op-=used;
e[i].v-=used,e[i^1].v+=used;
if(!op)break;
}
}
if(!flow)dis[u]=-1;
return flow;
}
int main()
{
scanf("%lld%lld",&n,&m);s=1,t=n;
ll u,v;ll w;
for(int i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&u,&v,&w);
add(u,v,w*mod+1);
}
while(bfs())ans+=dfs(s,inf);
printf("%lld %lld\n",ans/mod,ans%mod);
return 0;
}