http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1676
对顶点i,j,起点s=1,终点t=n,可以认为题意要求一组01矩阵use[i][j],使得aveCost=sigma(use[i][j]*cost[i][j])/sigma(use[i][j])最小,且{(i,j)|use[i][j]==1}是图的S-T割
定义F(e)=min(sigma(use[i][j]*(cost[i][j]-a))),明显,F(e)是目标式的变形,且当F(e)=0时,a就是aveCost,以cost[i][j]-a为容量建图,那么此时F(e)就是最小割容量.
二分确定最小割也即最大流为0时的a值,当流量恰好为0时取值最优,否则,若流量大于0不是最优,流量小于0不满足题意
注意:当确定a值时,cost[i][j]-a会导致负容量边,这些边可以使F(e)更小,所以直接加上即可
1 #include <cstdio> 2 #include <cstring> 3 #include<algorithm> 4 #include <queue> 5 #include <cmath> 6 using namespace std; 7 const int maxn=103; 8 const int maxm=403; 9 const int inf=0x7fffffff; 10 const double eps=1e-5; 11 int n,m; 12 int G[maxn][maxn]; 13 int e[maxn][maxn]; 14 int len[maxn]; 15 int num[maxn]; 16 int ind[maxn][maxn]; 17 double c[maxn][maxn]; 18 double f[maxn][maxn]; 19 int ans[maxm]; 20 int alen; 21 bool pars[maxn]; 22 int dis[maxn]; 23 int gap[maxn]; 24 25 void addedge(int f,int t){ 26 G[f][len[f]++]=t; 27 G[t][len[t]++]=f; 28 } 29 double build(double lamda){ 30 double flow=0; 31 memset(len,0,sizeof(len)); 32 for(int i=1;i<=n;i++){ 33 for(int j=0;j<num[i];j++){ 34 int to=e[i][j]; 35 if(i<to){ 36 f[i][to]=c[i][to]-lamda; 37 f[to][i]=c[i][to]-lamda; 38 if(f[i][to]<0){flow+=f[i][to];} 39 else{ 40 addedge(i,to); 41 } 42 } 43 } 44 } 45 memset(dis,0,sizeof(dis)); 46 memset(gap,0,sizeof(gap)); 47 gap[0]=n; 48 return flow; 49 } 50 51 double dfs(int s,double flow){ 52 if(s==n)return flow; 53 int mindis=n-1; 54 double tflow=flow,sub; 55 for(int i=0;i<len[s];i++){ 56 int to=G[s][i]; 57 if(f[s][to]>eps){ 58 if(dis[to]+1==dis[s]){ 59 sub=dfs(to,min(tflow,f[s][to])); 60 f[s][to]-=sub; 61 f[to][s]+=sub; 62 tflow-=sub; 63 if(dis[1]>=n)return flow-tflow; 64 if(tflow<eps)break; 65 } 66 mindis=min(mindis,dis[to]); 67 } 68 } 69 if(flow-tflow<eps){ 70 --gap[dis[s]]; 71 if(gap[dis[s]]==0)dis[1]=n; 72 else { 73 dis[s]=mindis+1; 74 ++gap[dis[s]]; 75 } 76 } 77 return flow-tflow; 78 } 79 80 double maxflow(double lamda){ 81 double flow=build(lamda); 82 while(dis[1]<n){ 83 flow+=dfs(1,inf); 84 } 85 return flow; 86 } 87 88 double binarysearch(double s,double e){ 89 if(s+eps>e){return s;} 90 double mid=(s+e)/2; 91 double flow=maxflow(mid); 92 if(fabs(flow)<eps)return mid; 93 else if(flow<-eps){ 94 return binarysearch(s,mid); 95 } 96 else { 97 return binarysearch(mid,e); 98 } 99 } 100 101 void fnd(double a){ 102 memset(pars,0,sizeof(pars)); 103 queue<int >que; 104 que.push(1); 105 pars[1]=true; 106 while(!que.empty()){ 107 int s=que.front();que.pop(); 108 for(int i=0;i<len[s];i++){ 109 int to=G[s][i]; 110 if(!pars[to]&&f[s][to]>eps){ 111 pars[to]=true;que.push(to); 112 } 113 } 114 } 115 alen=0; 116 for(int i=1;i<=n;i++){ 117 if(pars[i]){ 118 for(int j=0;j<num[i];j++){ 119 int to=e[i][j]; 120 if(!pars[to]){ 121 ans[alen++]=ind[i][to]; 122 } 123 else if(i<to&&c[i][to]+eps<a){ 124 ans[alen++]=ind[i][to]; 125 } 126 } 127 } 128 else { 129 for(int j=0;j<num[i];j++){ 130 int to=e[i][j]; 131 if(i<to&&!pars[to]&&c[i][to]+eps<a){ 132 ans[alen++]=ind[i][to]; 133 } 134 } 135 } 136 } 137 sort(ans,ans+alen); 138 } 139 140 int main(){ 141 bool first=true; 142 while(scanf("%d%d",&n,&m)==2){ 143 if(!first)puts(""); 144 else first=false; 145 memset(num,0,sizeof(num)); 146 int maxc=0,minc=1e7+1; 147 for(int i=1;i<=m;i++){ 148 int f,t,cost; 149 scanf("%d%d%d",&f,&t,&cost); 150 e[f][num[f]++]=t; 151 e[t][num[t]++]=f; 152 c[f][t]=c[t][f]=cost; 153 ind[f][t]= ind[t][f]=i; 154 maxc=max(maxc,cost); 155 minc=min(minc,cost); 156 } 157 double a=binarysearch(0,maxc+1); 158 fnd(a); 159 printf("%d\n",alen); 160 for(int i=0;i<alen;i++)printf("%d%c",ans[i],i==alen-1?'\n':' '); 161 } 162 return 0; 163 }