cjb-poi2010bridges

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <stack>
#include <cassert>
#define pb push_back
#define mp make_pair
#define rep(i,n) for(int i=1;i<=n;i++)
using namespace std;
struct node
{
    int x,y,w1,w2;
    void read(){ scanf("%d%d%d%d",&x,&y,&w1,&w2);  if (w1>w2)swap(x,y),swap(w1,w2); }
}a[2100];
int n,m;
int ru[1100],chu[1100],cnt;

#define N 1100
#define M 10100
struct EDGE { int adj, w, next; } edge[M];
int top, gh[N], nrl[N],S,T;
void addedge(int x, int y, int w) {
    edge[++top].adj = y;
    edge[top].w = w;
    edge[top].next = gh[x];
    gh[x] = top;
    edge[++top].adj = x;
    edge[top].w = 0;
    edge[top].next = gh[y];
    gh[y] = top;
}
int dist[N], q[N];
int bfs() {
    memset(dist, 0, sizeof(dist));
    q[1] = S; int head = 0, tail = 1; dist[S] = 1;
    while (head != tail) {
        int x = q[++head];
        for (int p=gh[x]; p; p=edge[p].next)
            if (edge[p].w && !dist[edge[p].adj]) {
                dist[edge[p].adj] = dist[x] + 1;
                q[++tail] = edge[p].adj;
            }
    }
    return dist[T];
}
int dinic(int x, int delta) {
    if (x==T) return delta;
    for (int& p=nrl[x]; p && delta; p=edge[p].next)
        if (edge[p].w && dist[x]+1 == dist[edge[p].adj]) {
            int dd = dinic(edge[p].adj, min(delta, edge[p].w));
            if (!dd) continue;
            edge[p].w -= dd;
            edge[p^1].w += dd;
            return dd;
        }
    return 0;
}
int work() {
    int ans = 0;
    while (bfs()) {
        memcpy(nrl, gh, sizeof(gh));
        int t; while (t = dinic(S, 2147483647)) ans += t;
    }
    return ans;
}

bool check(int limit)
{   
    for(int i=0;i<=n+1;i++)gh[i]=0; top=1;
    S=0; T=n+1;
    rep(i,m)
    {
        if (a[i].w1>limit)return 0;
        if (a[i].w2<=limit)addedge(a[i].x,a[i].y,1);
    }
    rep(i,n)
    {
        if (chu[i]>ru[i])addedge(S,i,(chu[i]-ru[i])/2);
        else if (chu[i]<ru[i])addedge(i,T,(ru[i]-chu[i])/2);
    }
    if (work()==cnt/2)return 1;
    return 0;
}
namespace DirectedGraph{
    int n,m,i,x,y,d[N],g[N],v[M],vis[M],nxt[M],ed;
    int ans[M],cnt;
    void add(int x,int y){
        //cout<<x<<" "<<y<<endl;
        d[x]++;d[y]--;
        v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
    }
    void dfs(int x){
        for(int&i=g[x];i;){
            if(vis[i]){i=nxt[i];continue;}
            vis[i]=1;
            int j=i;
            dfs(v[i]);
            ans[++cnt]=j;
        }
    }
    void solve(){
        dfs(1);
        for(i=m;i;i--)printf("%d%c",ans[i],i==1?'\n':' ');
    }
}
void print(int limit)
{
    check(limit);
    DirectedGraph::n=n;
    DirectedGraph::m=m;

    top=1;
    rep(i,m)
    {
        if (a[i].w2<=limit)
        {
            ++top;
            if (edge[top++].w==0)DirectedGraph::add(a[i].y,a[i].x);
            else DirectedGraph::add(a[i].x,a[i].y);
        }else DirectedGraph::add(a[i].x,a[i].y);
    }
    cout<<limit<<endl;
    DirectedGraph::solve();
}
int main()
{
    cin>>n>>m;
    rep(i,m)a[i].read();
    int l=1; int r=1000;
    rep(i,n)ru[i]=chu[i]=0;
    rep(i,m)chu[a[i].x]++,ru[a[i].y]++;
    cnt=0;
    rep(i,n)
    {
        if ((chu[i]-ru[i])%2!=0){ puts("NIE"); return 0; }
        cnt+=abs(chu[i]-ru[i])/2;
    }

    while (l<r)
    {
        int mid=(l+r)/2;
        if (check(mid))r=mid; else l=mid+1;
    }
    print(l);
}
}}}
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <stack>
#include <cassert>
#define pb push_back
#define mp make_pair
#define rep(i,n) for(int i=1;i<=n;i++)
using namespace std;
struct node
{
    int x,y,w1,w2;
    void read(){ scanf("%d%d%d%d",&x,&y,&w1,&w2);  if (w1>w2)swap(x,y),swap(w1,w2); }
}a[2100];
int n,m;
int ru[1100],chu[1100],cnt;
#define N 1100
#define M 10100
struct EDGE { int adj, w, next; } edge[M];
int top, gh[N], nrl[N],S,T;
void addedge(int x, int y, int w) {
    edge[++top].adj = y;
    edge[top].w = w;
    edge[top].next = gh[x];
    gh[x] = top;
    edge[++top].adj = x;
    edge[top].w = 0;
    edge[top].next = gh[y];
    gh[y] = top;
}
int dist[N], q[N];
int bfs() {
    memset(dist, 0, sizeof(dist));
    q[1] = S; int head = 0, tail = 1; dist[S] = 1;
    while (head != tail) {
        int x = q[++head];
        for (int p=gh[x]; p; p=edge[p].next)
            if (edge[p].w && !dist[edge[p].adj]) {
                dist[edge[p].adj] = dist[x] + 1;
                q[++tail] = edge[p].adj;
            }
    }
    return dist[T];
}
int dinic(int x, int delta) {
    if (x==T) return delta;
    for (int& p=nrl[x]; p && delta; p=edge[p].next)
        if (edge[p].w && dist[x]+1 == dist[edge[p].adj]) {
            int dd = dinic(edge[p].adj, min(delta, edge[p].w));
            if (!dd) continue;
            edge[p].w -= dd;
            edge[p^1].w += dd;
            return dd;
        }
    return 0;
}
int work() {
    int ans = 0;
    while (bfs()) {
        memcpy(nrl, gh, sizeof(gh));
        int t; while (t = dinic(S, 2147483647)) ans += t;
    }
    return ans;
}
bool check(int limit)
{   
    for(int i=0;i<=n+1;i++)gh[i]=0; top=1;
    S=0; T=n+1;
    rep(i,m)
    {
        if (a[i].w1>limit)return 0;
        if (a[i].w2<=limit)addedge(a[i].x,a[i].y,1);
    }
    rep(i,n)
    {
        if (chu[i]>ru[i])addedge(S,i,(chu[i]-ru[i])/2);
        else if (chu[i]<ru[i])addedge(i,T,(ru[i]-chu[i])/2);
    }
    if (work()==cnt/2)return 1;
    return 0;
}
namespace DirectedGraph{
    int n,m,i,x,y,d[N],g[N],v[M],vis[M],nxt[M],ed;
    int ans[M],cnt;
    void add(int x,int y){
        //cout<<x<<" "<<y<<endl;
        d[x]++;d[y]--;
        v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
    }
    void dfs(int x){
        for(int&i=g[x];i;){
            if(vis[i]){i=nxt[i];continue;}
            vis[i]=1;
            int j=i;
            dfs(v[i]);
            ans[++cnt]=j;
        }
    }
    void solve(){
        dfs(1);
        for(i=m;i;i--)printf("%d%c",ans[i],i==1?'\n':' ');
    }
}
void print(int limit)
{
    check(limit);
    DirectedGraph::n=n;
    DirectedGraph::m=m;
    top=1;
    rep(i,m)
    {
        if (a[i].w2<=limit)
        {
            ++top;
            if (edge[top++].w==0)DirectedGraph::add(a[i].y,a[i].x);
            else DirectedGraph::add(a[i].x,a[i].y);
        }else DirectedGraph::add(a[i].x,a[i].y);
    }
    cout<<limit<<endl;
    DirectedGraph::solve();
}
int main()
{
    cin>>n>>m;
    rep(i,m)a[i].read();
    int l=1; int r=1000;
    rep(i,n)ru[i]=chu[i]=0;
    rep(i,m)chu[a[i].x]++,ru[a[i].y]++;
    cnt=0;
    rep(i,n)
    {
        if ((chu[i]-ru[i])%2!=0){ puts("NIE"); return 0; }
        cnt+=abs(chu[i]-ru[i])/2;
    }
    while (l<r)
    {
        int mid=(l+r)/2;
        if (check(mid))r=mid; else l=mid+1;
    }
    print(l);
}