Base Station
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 65768/32768 K (Java/Others)Total Submission(s): 1788 Accepted Submission(s): 758
When complete building, two places which both have stations can communicate with each other.
Besides, according to the marketing department, the company has received m requirements. The ith requirement is represented by three integers Ai, Bi and Ci, which means if place Ai and Bi can communicate with each other, the company will get Ci profit.
Now, the company wants to maximize the profits, so maybe just part of the possible locations will be chosen to build new stations. The boss wants to know the maximum profits.
The first line has two integers n (0<n<=5000) and m (0<m<=50000).
The second line has n integers, P1 through Pn, describes the cost of each location.
Next m line, each line contains three integers, Ai, Bi and Ci, describes the ith requirement.
分析:最大權閉合圖模型。
代碼:
//Isap算法,複雜度O(n^2m)
#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
typedef long long ll; //記得必要的時候改成無符號
const int maxn=55005;
const int maxm=1000005;
const int INF=1000000000;
struct EdgeNode
{
int from;
int to;
int cost;
int next;
}edge[maxm];
int head[maxn],cnt;
void add(int x,int y,int z)
{
edge[cnt].from=x;edge[cnt].to=y;edge[cnt].cost=z;edge[cnt].next=head[x];head[x]=cnt++;
edge[cnt].from=y;edge[cnt].to=x;edge[cnt].cost=0;edge[cnt].next=head[y];head[y]=cnt++;
}
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}
int S,T,n,m;
int d[maxn],gap[maxn],curedge[maxn],pre[maxn];
//curedge[]爲當前弧數組,pre爲前驅數組
int sap(int S,int T,int n) //n爲點數
{
int cur_flow,flow_ans=0,u,tmp,neck,i;
memset(d,0,sizeof(d));
memset(gap,0,sizeof(gap));
memset(pre,-1,sizeof(pre));
for(i=0;i<=n;i++)curedge[i]=head[i]; //初始化當前弧爲第一條鄰接表
gap[0]=n;
u=S;
while(d[S]<n) //當d[S]>=n時,網絡中肯定出現了斷層
{
if(u==T)
{
cur_flow=INF;
for(i=S;i!=T;i=edge[curedge[i]].to)
{ //增廣成功,尋找瓶頸邊
if(cur_flow>edge[curedge[i]].cost)
{
neck=i;
cur_flow=edge[curedge[i]].cost;
}
}
for(i=S;i!=T;i=edge[curedge[i]].to)
{ //修改路徑上的邊容量
tmp=curedge[i];
edge[tmp].cost-=cur_flow;
edge[tmp^1].cost+=cur_flow;
}
flow_ans+=cur_flow;
u=neck; //下次增廣從瓶頸邊開始
}
for(i=curedge[u];i!=-1;i=edge[i].next)
if(edge[i].cost&&d[u]==d[edge[i].to]+1)
break;
if(i!=-1)
{
curedge[u]=i;
pre[edge[i].to]=u;
u=edge[i].to;
}
else
{
if(0==--gap[d[u]])break; //gap優化
curedge[u]=head[u];
for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
if(edge[i].cost)
tmp=min(tmp,d[edge[i].to]);
d[u]=tmp+1;
++gap[d[u]];
if(u!=S)u=pre[u]; //重標號並且從當前點前驅重新增廣
}
}
return flow_ans;
}
int main()
{
int ans,i,x,y,z,sum;
while(~scanf("%d%d",&n,&m))
{
sum=0;
init(); S=0; T=n+m+1; ans=n;
for(i=1;i<=n;i++){
scanf("%d",&x);
add(i,T,x);
}
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
ans++;
sum+=z;
add(S,ans,z);
add(ans,x,INF);
add(ans,y,INF);
}
n=T+1;
printf("%d\n",sum-sap(S,T,n));
}
return 0;
}