时间限制:20000ms
单点时限:1000ms
内存限制:256MB
描述
在 A 国有一个秘密特工组织,这个特工组织是由若干对双人组合构成的
现在特工组织有一批新人加入,为了防止背叛,组织规定来自相同城市的人不能配对在一起
现在已知 A 国有 n 个城市,且新人中来自第 i 个城市的有 ai 人,求最多组成几个配对
输入
第一行一个正整数 n
第二行 n 个数,第 i 个数是 ai
1 ≤ n ≤ 103
0 ≤ ai ≤ 109
输出
输出最多组成几个配对
样例输入
3 1 2 3
样例输出
3
思路:
本来这道题不用网络流,就可以的。不过感觉可以做,就试试模板。
直接S连所有城市 i,流量为人数,T 连所有城市拆的点n+i 流量为人数。
i 与 除了它自己的城市连边,流量为min(两个城市人数)。
因为又重复的值,跑一遍最大流/2,就是答案。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std ;
#define RPEF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define copy( a , x ) memcpy ( a , x , sizeof a )
typedef long long LL ;
const int MAXN = 150000 ;
const int MAXE = 10000000 ;
const int MAXQ = 10000000 ;
const LL INF = 1e15 ;
struct Edge {
int v , n ;
LL c ;
Edge ( int var = 0 , LL cap = 0 , int next = 0 ) :
v ( var ) , c ( cap ) , n ( next ) {}
} ;
struct netWork {
Edge edge[MAXE] ;
int adj[MAXN] , cntE ;
int cur[MAXN] , d[MAXN] , num[MAXN] , pre[MAXN] ;
bool vis[MAXN] ;
int Q[MAXQ] , head , tail ;
int s , t , nv ;
LL flow ;
void init () {
cntE = 0 ;
memset(adj,-1,sizeof(adj));
}
void addedge ( int u , int v , LL c , LL rc = 0 ) {
edge[cntE] = Edge ( v , c , adj[u] ) ;
adj[u] = cntE ++ ;
edge[cntE] = Edge ( u , rc , adj[v] ) ;
adj[v] = cntE ++ ;
}
void rev_Bfs () {
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
d[t] = 0 ;
vis[t] = 1 ;
head = tail = 0 ;
Q[tail ++] = t ;
num[0] = 1 ;
while ( head != tail ) {
int u = Q[head ++] ;
for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
int v = edge[i].v ;
if ( vis[v] )
continue ;
vis[v] = 1 ;
d[v] = d[u] + 1 ;
++ num[d[v]] ;
Q[tail ++] = v ;
}
}
}
LL ISAP () {
copy ( cur , adj ) ;
rev_Bfs () ;
flow = 0 ;
int i , u = pre[s] = s ;
while ( d[s] < nv ) {
if ( u == t ) {
LL f = INF ;
int pos ;
for ( i = s ; i != t ; i = edge[cur[i]].v )
if ( f > edge[cur[i]].c )
f = edge[cur[i]].c , pos = i ;
for ( i = s ; i != t ; i = edge[cur[i]].v )
edge[cur[i]].c -= f , edge[cur[i] ^ 1].c += f ;
u = pos ;
flow += f ;
}
for ( i = cur[u] ; ~i ; i = edge[i].n )
if ( edge[i].c && d[u] == d[edge[i].v] + 1 )
break ;
if ( ~i ) {
cur[u] = i ;
pre[edge[i].v] = u ;
u = edge[i].v ;
}
else {
if ( 0 == ( -- num[d[u]] ) )
break ;
int mmin = nv ;
for ( i = adj[u] ; ~i ; i = edge[i].n )
if ( edge[i].c && mmin > d[edge[i].v] )
cur[u] = i , mmin = d[edge[i].v] ;
d[u] = mmin + 1 ;
++ num[d[u]] ;
u = pre[u] ;
}
}
return flow ;
}
} ;
netWork net ;
int n,m;
int a[2100];
void work () {
net.init () ;
net.s = 0 , net.t = 2*n+1, net.nv = net.t + 1 ;
for(int i=1;i<=n;i++)
{
net.addedge(net.s,i,a[i]);
net.addedge(n+i,net.t,a[i]);
for(int j=1;j<=n;j++)
{
if(i==j)continue;
net.addedge(i,n+j,min(a[i],a[j]));
}
}
LL flow = net.ISAP () ;
printf ( "%lld\n" ,flow/2) ;
}
int main () {
memset(a,0,sizeof(a));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
work () ;
return 0 ;
}