您的位置:首页 > 其它

tsinsen A1220. 复杂的大门(陈许旻)

2016-02-26 20:30 176 查看
A1220. 复杂的大门(陈许旻)

时间限制:1.0s 内存限制:512.0MB
总提交次数:132
AC次数:74 平均分:67.84

试题来源

  2011中国国家集训队命题答辩

问题描述

  你去找某bm玩,到了门口才发现要打开他家的大门不是一件容易的事……

  他家的大门外有n个站台,用1到n的正整数编号。你需要对每个站台访问一定次数以后大门才能开启。站台之间有m个单向的传送门,通过传送门到达另一个站台不需要花费任何代价。而如果不通过传送门,你就需要乘坐公共汽车,并花费1单位的钱。值得庆幸的是,任意两个站台之间都有公共汽车直达。

  现在给你每个站台必须访问的次数Fi,对于站台i,你必须恰好访问Fi次(不能超过)。

  我们用u、v、w三个参数描述一个传送门,表示从站台u到站台v有一个最多可以使用w次的传送门(不一定要使用w次)。值得注意的是,对于任意一对传送门(u1,v1)和(u2,v2),如果有u1<u2,则有v1≤v2;如果有v1<v2,则有u1≤u2;且u1=u2和v1=v2不同时成立。

  你可以从任意的站台开始,从任意的站台结束。出发去开始的站台需要花费1单位的钱。你需要求出打开大门最少需要花费多少单位的钱。

输入格式

  第一行包含两个正整数n、m,意义见题目描述。

  第二行包含n个正整数,第i个数表示Fi。

  接下来有m行,每行有三个正整数u、v、w,表示从u到v有一个可以使用w次的传送门。

输出格式

  输出一行一个整数,表示打开大门最少花费的钱数。

样例输入

4 3

5 5 5 5

1 2 1

3 2 1

3 4 1

样例输出

17

数据规模及约定

  有20%的数据满足n≤10,m≤50;对于所有的w、Fi,满足1≤w,Fi≤10。有50%的数据满足n≤1000,m≤10000。100%的数据满足1≤n≤10000,1≤m≤100000;对于所有的u、v,满足1≤u,v≤n,u≠v;对于所有的w、Fi,满足1≤w,Fi≤50000。

  以上的每类数据中都存在50%的数据满足对于所有的w、Fi,有w=Fi=1。

  时限1s

题解:此题是一道网络流的题目。输出打开大门最少花费的钱数实际上就是求总的经过的数目-最大使用传送门的次数,而最多使用传送门的次数可以用最大流来求解。

首先拆点,把每个点拆成起点和终点,然后从源点向所有的起点连边,权值为该点所需要的经过次数,然后从终点向汇点连边,权值为该点所需要的经过次数,然后处理传送门的信息,传送门的起点向终点连边,权值为传送门最大使用的次数。这样就可以跑最大流啦。因为是二分图,所有果断选择dinic。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int n,m,i,j,f[10003],sum=0;
int tot,next[400003],point[30000],v[400003],remain[400003];
int deep[30000],cur[30000];
const int inf=1e9;
void add(int x,int y,int z)
{
tot++; next[tot]=point[x]; point[x]=tot; remain[tot]=z; v[tot]=y;
tot++; next[tot]=point[y]; point[y]=tot; remain[tot]=0; v[tot]=x;
}
bool bfs(int s,int t)
{
memset(deep,0x7f,sizeof(deep));
for (int i=s;i<=t;i++)
cur[i]=point[i];
deep[s]=0;  queue<int> p; p.push(s);
while (!p.empty())
{
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=next[i])
if (remain[i]&&deep[v[i]]>inf)
{
deep[v[i]]=deep[now]+1;
p.push(v[i]);
}
}
if (deep[t]>inf)  return false;
else return true;
}
int dfs(int now ,int t,int limit)
{
if (!limit||now==t)  return limit;
int flow=0,f;
for (int i=cur[now];i!=-1;i=next[i])
{
cur[now]=i;
if (deep[v[i]]==deep[now]+1&&(f=dfs(v[i],t,min(limit,remain[i]))))
{
flow+=f; limit-=f;
remain[i]-=f; remain[i^1]+=f;
if (!limit)  break;
}
}
return flow;
}
int dinic(int s,int t)
{
int ans=0;
while (bfs(s,t))
ans+=dfs(s,t,inf);
return ans;
}
int main()
{
tot=-1; memset(next,-1,sizeof(next)); memset(point,-1,sizeof(point));
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
scanf("%d",&f[i]); sum+=f[i];
add(0,i,f[i]);
add(i+n,2*n+1,f[i]);
}
for (i=1;i<=m;i++)
{
int x,y,z; scanf("%d%d%d",&x,&y,&z);
add(x,y+n,z);
}
printf("%d",sum-dinic(0,2*n+1));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: