题意:给定一个带权无向图G(V,E),每条边有个权值w,求将点s和点t分开的一个边割集C,使该割集的平均边权最小。
思路:参见Amber的《最小割模型在信息学竞赛中的应用》。大体就是构造新函数g(x),找到g(x)=0的x,x即为平均边权最小值。
// file name: zoj2676.cpp //
// author: kereo //
// create time: 2014年10月31日 星期五 15时33分36秒 //
//***********************************//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int sigma_size=26;
const int MAXN=500+100;
const double eps=1e-6;
const int inf=0x7fffffff;
const int mod=1000000000+7;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
int n,m,edge_cnt,top;
int que[MAXN],s[MAXN];
int head[MAXN],depth[MAXN],cur[MAXN],gap[MAXN],vis[MAXN];
struct node{
int u,v;
double w;
}p[MAXN];
struct Edge{
int v,next;
double cap,flow;
}edge[MAXN<<1];
void init(){
edge_cnt=top=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,double w){
edge[edge_cnt].v=v;
edge[edge_cnt].cap=w; edge[edge_cnt].flow=0;
edge[edge_cnt].next=head[u]; head[u]=edge_cnt++;
}
void bfs(int st,int ed){
memset(depth,-1,sizeof(depth));
memset(gap,0,sizeof(gap));
int front=0,rear=0; gap[0]=1;
depth[ed]=0; que[rear++]=ed;
while(front!=rear){
int u=que[front++];
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(depth[v]!=-1) continue;
que[rear++]=v;
depth[v]=depth[u]+1; gap[depth[v]]++;
}
}
}
double isap(int st,int ed){
bfs(st,ed);
memcpy(cur,head,sizeof(head));
top=0;
int u=st;
double ans=0;
while(depth[st]<n){
if(u == ed){
double Min=inf;
int inser;
for(int i=0;i<top;i++){
if(edge[s[i]].cap-edge[s[i]].flow+eps<Min){
Min=edge[s[i]].cap-edge[s[i]].flow;
inser=i;
}
}
for(int i=0;i<top;i++){
edge[s[i]].flow+=Min; edge[s[i]^1].flow-=Min;
}
ans+=Min; top=inser;
u=edge[s[top]^1].v;
continue;
}
int flag=0;
int v;
for(int i=cur[u];i!=-1;i=edge[i].next){
v=edge[i].v;
if(edge[i].flow+eps<edge[i].cap && depth[v]+1 == depth[u]){
flag=1; cur[u]=i;
break;
}
}
if(flag){
s[top++]=cur[u]; u=v;
continue;
}
int d=n;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(edge[i].flow+eps<edge[i].cap && depth[v]<d){
d=depth[v];
cur[u]=i;
}
}
gap[depth[u]]--;
if(!gap[depth[u]]) return ans;
depth[u]=d+1; gap[depth[u]]++;
if(u!=st) u=edge[s[--top]^1].v;
}
return ans;
}
void dfs(int u){
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(edge[i].flow+eps<edge[i].cap && !vis[v]){
vis[v]=1;
dfs(v);
}
}
}
void solve(){
double l=0,r=1e7,mid;
while(l+eps<r){
mid=(l+r)/2;
double ans=0;
init();
for(int i=1;i<=m;i++){
if(p[i].w+eps<mid)
ans+=p[i].w-mid;
else{
addedge(p[i].u,p[i].v,p[i].w-mid);
addedge(p[i].v,p[i].u,p[i].w-mid);
}
}
ans+=isap(1,n);
if(ans>eps)
l=mid;
else
r=mid;
}
memset(vis,0,sizeof(vis));
vis[1]=1;
dfs(1);
int res=0;
for(int i=1;i<=m;i++){
if(p[i].w+eps<mid || (vis[p[i].u]+vis[p[i].v]) == 1)
res++;
}
printf("%d\n",res);
int flag=1;
for(int i=1;i<=m;i++){
if(p[i].w+eps<mid || (vis[p[i].u]+vis[p[i].v]) == 1){
if(flag){
printf("%d",i);
flag=0;
}
else
printf(" %d",i);
}
}
printf("\n");
}
int main()
{
int flag=0;
while(~scanf("%d%d",&n,&m)){
if(!flag)
flag=1;
else
printf("\n");
for(int i=1;i<=m;i++)
scanf("%d%d%lf",&p[i].u,&p[i].v,&p[i].w);
solve();
}
return 0;
}