题目地址:
http://codeforces.com/gym/100204/attachments
思路:
1.即要求求:
其中Xi=1代表选择该条边,为0代表不选择该边。
2.转化为:
即:
二分ans,设置所有边为W-ans,若一条边小于0,则直接将其加入(该边小于平均值,加入则会使最终结果更小),设所有负权边和为sum。求最小割,判断最小割+sum是否小于0,即可。(若小于等于0,则在ans在[l,mid]内,否则ans在[mid,r]内)
3.输出答案时,dfs染色,从起点S开始,只经过flow<cap的边,标记经过的点(vis[u]=1)。若对于边(u,v),vis[u]+vis[v]=1,则该边为割边,将其输出,同时将所有负权边输出。
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define S 1
#define T n
#define debug
using namespace std;
const double eps=1e-6;
const int maxn=100+50;
const int maxm=800+50;
const int INF=0x3f3f3f3f;
struct Edge
{
int from, to;
double cap, flow;
Edge(int a,int b,double c,double d):from(a),to(b),cap(c),flow(d) {}
};
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
struct Dinic
{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n)
{
this->n=n;
for(int i = 0; i <= n; i++) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, double cap)
{
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
vis[s] = 1;
d[s] = 0;
while(!Q.empty())
{
int x = Q.front();
Q.pop();
for(int i = 0; i < G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if(!vis[e.to] && dcmp(e.cap - e.flow)>0)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
double DFS(int x, double a)
{
if(x == t || dcmp(a) == 0) return a;
double flow = 0, f;
for(int& i = cur[x]; i < G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0)
{
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(dcmp(a) == 0) break;
}
}
return flow;
}
double MaxFlow(int s, int t)
{
this->s = s;
this->t = t;
double flow = 0;
while(BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
};
struct Node
{
int u,v,w;
};
Dinic g;
int n,m;
int vis[maxn];
int flag[maxn][maxn];
Node e[maxm];
double check(double x,int id)
{
g.init(n);
double sum=0.0;
for(int i=0; i<m; i++)
{
if(dcmp(e[i].w-x)>0)
{
g.addEdge(e[i].u,e[i].v,e[i].w-x);
g.addEdge(e[i].v,e[i].u,e[i].w-x);
}
//cout<<x<<" "<<e[i].u<<" "<<e[i].v<<" "<<e[i].w-x<<endl;
if(id&&dcmp(e[i].w-x)<0) flag[e[i].u][e[i].v]=flag[e[i].v][e[i].u]=1;
sum+=min(e[i].w-x,0.0);
}
//cout<<"***********"<<endl;
return sum+g.MaxFlow(S,T);
}
void dfs(int u)
{
vis[u]=1;
for(int i=0; i<g.G[u].size(); i++)
{
Edge& e=g.edges[g.G[u][i]];
if(!vis[e.to]&&dcmp(e.flow-e.cap)<0)
{
dfs(e.to);
}
}
}
void print()
{
int tot=0;
vector<int> ans;
for(int i=0; i<m; i++)
{
if(flag[e[i].u][e[i].v]||vis[e[i].u]^vis[e[i].v])
{
tot++;
ans.push_back(i+1);
}
}
printf("%d\n",tot);
for(int i=0; i<ans.size(); i++)
{
if(i==0) printf("%d",ans[i]);
else printf(" %d",ans[i]);
}
printf("\n");
}
int main()
{
#ifdef debug
freopen("network.in","r",stdin);
freopen("network.out","w",stdout);
#endif // debug
scanf("%d%d",&n,&m);
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
double l=0.0,r=1e6,ans=0.0;
while(fabs(r-l)>eps)
{
double mid=(l+r)/2;
if(dcmp(check(mid,0))<=0)
{
r=mid;
ans=mid;
//cout<<ans<<" "<<check(mid)<<endl;
}
else
{
l=mid;
}
}
check(ans,1);
dfs(S);
print();
return 0;
}