HackerRank Weekly Challenges - Week 2 5問目
problem statement(コンテストページ)
problem statement
ノード数 $N$,枝数 $M$ の無向グラフが与えられる.
このグラフの枝はランダムに $2$ ノードを選んで作られていて,同じ節点間に複数の枝があったり,自分自身をつなぐ枝もあり得る.
枝 $k$ にはコスト $C_k$ が与えられ,これもランダムに選ばれている.
頂点 $i$ と $j$ が連結でなくなるように枝を削除することを考える.
ここで,削除する枝のコストの和の最小値を $w_{ij}$ とする.
全てのノード間の $w_{ij}$ の積
$\displaystyle \prod_{1 \leq i < j \leq N} w_{ij}$
を ${\rm mod}\ 1000000007\ (10^9+7)$ で求める問題.
全ての接点間の最小カット $=$ 最大流を求めれば良い.
無向グラフの全接点間の最大流を求めるGomory-HuアルゴリズムでGomory-Hu treeを用いれば良い.
これは,$N$ 回の最大流を流せば求めることができる.
#include<bits/stdc++.h>
using namespace std;
#define REP(i,a,b) for(i=a;i<b;i++)
#define rep(i,n) REP(i,0,n)
#define mygc(c) (c)=getchar_unlocked()
#define mypc(c) putchar_unlocked(c)
void reader(int *x){int k,m=0;*x=0;for(;;){mygc(k);if(k=='-'){m=1;break;}if('0'<=k&&k<='9'){*x=k-'0';break;}}for(;;){mygc(k);if(k<'0'||k>'9')break;*x=(*x)*10+k-'0';}if(m)(*x)=-(*x);}
void reader(int *x, int *y){reader(x);reader(y);}
void reader(int *x, int *y, int *z){reader(x);reader(y);reader(z);}
void writer(int x, char c){int i,sz=0,m=0;char buf[10];if(x<0)m=1,x=-x;while(x)buf[sz++]=x%10,x/=10;if(!sz)buf[sz++]=0;if(m)mypc('-');while(sz--)mypc(buf[sz]+'0');mypc(c);}
#define ll long long
#define MD 1000000007
#define INT_INF 1000000000
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define INT_LIST_MAX_FLOW_NODE 602
int intLmfEdge[INT_LIST_MAX_FLOW_NODE][INT_LIST_MAX_FLOW_NODE];
int intLmfFlow[INT_LIST_MAX_FLOW_NODE][INT_LIST_MAX_FLOW_NODE];
int intLmfInv[INT_LIST_MAX_FLOW_NODE][INT_LIST_MAX_FLOW_NODE];
int intLmfEdgeSize[INT_LIST_MAX_FLOW_NODE],intLmfEdgeMemory[INT_LIST_MAX_FLOW_NODE];
int intLmfLevel[INT_LIST_MAX_FLOW_NODE];
void intListMaxFlowLevelize(int n,int st,int ed){
int i,j,k,t;
int q[INT_LIST_MAX_FLOW_NODE],q_st,q_size;
rep(i,n) intLmfLevel[i]=-1; intLmfLevel[st]=0; q_st=0; q_size=1; q[0]=st;
while(q_size){
i=q[q_st++]; q_size--; t=intLmfLevel[i]+1;
rep(j,intLmfEdgeSize[i]) if(intLmfFlow[i][j]){
k=intLmfEdge[i][j]; if(intLmfLevel[k]!=-1) continue;
intLmfLevel[k]=t; q[q_st+q_size++]=k; if(k==ed) return;
}
}
}
int intListMaxFlowFlow(int i,int ed,int lim){
int j,k,ret=0,t,s,ji;
if(i==ed) return lim;
rep(j,intLmfEdgeSize[i]) if(intLmfFlow[i][j]){
k=intLmfEdge[i][j]; if(intLmfLevel[k]<=intLmfLevel[i]) continue;
s=lim; if(s>intLmfFlow[i][j]) s=intLmfFlow[i][j];
t=intListMaxFlowFlow(k,ed,s); if(!t) continue;
ret+=t; lim-=t; ji=intLmfInv[i][j];
intLmfFlow[i][j]-=t; intLmfFlow[k][ji]+=t;
if(!lim) break;
}
return ret;
}
int intListMaxFlow(int n,int st,int ed){
int ret=0;
for(;;){
intListMaxFlowLevelize(n,st,ed); if(intLmfLevel[ed]==-1) break;
ret += intListMaxFlowFlow(st,ed,INT_INF);
}
return ret;
}
void intListMaxFlowEdgeInit(){
int i;
rep(i,INT_LIST_MAX_FLOW_NODE) intLmfEdgeSize[i]=0;
}
void intListMaxFlowEdgeInitAdv(int n){
int i;
rep(i,n) intLmfEdgeSize[i]=0;
}
void intListMaxFlowEdgeAdd(int n1,int n2,int f1,int f2){
int s1=intLmfEdgeSize[n1]++, s2=intLmfEdgeSize[n2]++;
intLmfEdge[n1][s1]=n2; intLmfEdge[n2][s2]=n1;
intLmfFlow[n1][s1]=f1; intLmfFlow[n2][s2]=f2;
intLmfInv[n1][s1]=s2; intLmfInv[n2][s2]=s1;
}
void intListMaxFlowDfs(int node,int start,int res[]){
int i,j,k;
int st[INT_LIST_MAX_FLOW_NODE], st_size=0;
rep(i,node) res[i]=0; res[start]=1; st[st_size++]=start;
while(st_size){
i=st[--st_size];
rep(k,intLmfEdgeSize[i]) if(intLmfFlow[i][k]){
j=intLmfEdge[i][k]; if(res[j]) continue;
res[j]=1; st[st_size++]=j;
}
}
}
/* Gomory-Hu's Algorithm ? */
/* int edge[][]が各枝のFlow,対称性があるedge[i][j]=edge[j][i] */
/* int res[][]に任意の2点間のmax-flowを計算する */
int edge[600][600], res[600][600];
void intMaxflowAnyPairOfNode(int node,void *WorkMemory){
int i,j,a,b,flow;
int *p, *fst;
p=(int*)WorkMemory; WorkMemory=(void*)(p+node);
fst=(int*)WorkMemory;
rep(i,node) p[i]=0;
rep(i,node) rep(j,node) res[i][j]=INT_INF;
REP(i,1,node){
intListMaxFlowEdgeInitAdv(node);
rep(a,node) REP(b,a+1,node) if(edge[a][b]) intListMaxFlowEdgeAdd(a,b,edge[a][b],edge[b][a]);
flow = intListMaxFlow(node,i,p[i]);
intListMaxFlowDfs(node,i,fst);
REP(j,i+1,node) if(fst[j] && p[i]==p[j]) p[j]=i;
res[i][p[i]]=res[p[i]][i]=flow;
rep(j,i) res[i][j]=res[j][i]=MIN(flow,res[p[i]][j]);
}
}
int main(){
int i, j, k, M, N;
ll ans;
void *mem=malloc(100000000);
reader(&N, &M);
rep(i,N) rep(j,N) edge[i][j] = 0;
while(M--){
reader(&i,&j,&k);
i--; j--;
edge[i][j] += k;
edge[j][i] += k;
}
intMaxflowAnyPairOfNode(N, mem);
ans = 1;
rep(i,N) REP(j,i+1,N) ans = (ans * res[i][j]) % MD;
writer((int)ans, '\n');
return 0;
}
Current time: 2024年04月19日07時57分18秒
Last modified: 2014年09月22日23時25分24秒 (by laycrs)
Tags: Competitive_Programming HackerRank HackerRank_w2
トップページに戻る
Logged in as: unknown user (not login)