Gym 100204G Network Wars(最小割+0/1分數規劃)

題目地址: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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章