1. 程式人生 > >[HihoCoder-1389] 最大流 仍舊是建圖

[HihoCoder-1389] 最大流 仍舊是建圖

題目連結:https://vjudge.net/problem/HihoCoder-1389

題目思路:首先,看到題目,能想到用最大流,可是那個公式始終不能處理,一開始想先二分u,再二分c,因為u增加的快,然後化了一個圖,c二分的話可能某些點就不在原上的,c就會過多,後來一想,算了,列舉吧,然後瘋狂T,想想也覺得會T,就不知道咋辦了,後來看到題解是將最大卡住,因為每次C都在變大,如果u不比之前的小的話,答案也就不比之前的小了,另外還有個優化是,當u取sum/n時仍舊比他大,也要break掉,還有就是我一開始的二分是有問題的,複雜度會高。還有就是sap複雜度是比dinic低的,sap跑1003ms,dinic跑1713ms

 

AC程式碼

#include<queue>
#include<vector>
#include<set>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

#define maxn 500
#define maxm 100000
#define inf 0x3f3f3f3f
int first[maxn];
int edge_num;
int lev[maxn];
int vis[maxn];
int mark[103];
int n,m;
int sum;
struct edge{
    int u,v;
    int cap;
    int next;
}e[maxm];
struct node{
    int dis;
    int x;
    int y;
    node(int a=0,int b=0,int c=0)
    {
        dis=a;
        x=b;
        y=c;
    }
};
int low;
int high;
int xxx;
vector<node>nodes;
struct point{
    int x;
    int y;
    int s=0;
    point(int a=0,int b=0,int c=0)
    {
        x=a;
        y=b;
        s=c;
    }
};
vector<point>fac;
vector<point>pku;

void init()
{
    edge_num=0;
    memset(first,-1,sizeof(first));
}

void add_edge(int u,int v,int c)
{
    e[edge_num].u=u;
    e[edge_num].v=v;
    e[edge_num].cap=c;
    e[edge_num].next=first[u];
    first[u]=edge_num++;
    e[edge_num].u=v;
    e[edge_num].v=u;
    e[edge_num].cap=0;
    e[edge_num].next=first[v];
    first[v]=edge_num++;
}

int Dinic_spath(int s,int t)
{
    queue<int>q;
    q.push(s);
    memset(lev,-1,sizeof(lev));
    memset(vis,0,sizeof(vis));
    lev[s]=0;
    while(!q.empty())
    {
        int u=q.front();
        vis[u]=0;
        q.pop();
        for(int k=first[u];k!=-1;k=e[k].next)
        {
            int v=e[k].v;
            if(lev[v]==-1&&e[k].cap>0)
            {
                lev[v]=lev[u]+1;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return lev[t]!=-1;
}

int Dinic_dfs(int u,int t,int flow)
{
    int cost=0;
    if(u==t) return flow;
    for(int k=first[u];k!=-1;k=e[k].next)
    {
        int v=e[k].v;
        if(lev[v]==lev[u]+1&&e[k].cap>0)
        {
            int minn=Dinic_dfs(v,t,min(e[k].cap,flow-cost));
            if(minn>0)
            {
                e[k].cap=e[k].cap-minn;
                e[k^1].cap=e[k^1].cap+minn;
                cost+=minn;
                if(cost==flow) break;
            }
            else
                lev[v]=-1;
        }
    }
    return cost;
}

bool cmp(const node &a,const node &b)
{
    return a.dis<b.dis;
}

bool judge(int mid,int s,int t)
{
    init();
    for(int i=0;i<m;++i)
        add_edge(s,i+1,mid);
    for(int i=0;i<n;++i)
        add_edge(m+i+1,t,fac[i].s);
    for(int i=0;i<=xxx;++i)
        add_edge(nodes[i].x+1,m+1+nodes[i].y,inf);
    int f=0;
    while(Dinic_spath(s,t))
        f+=Dinic_dfs(s,t,inf);
    return f>=sum;
}

int main()
{
    while(scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)
            break;
        sum=0;
        fac.clear();
        pku.clear();
        nodes.clear();
        int x,y,z;
        for(int i=1;i<=n;++i)
        {
            scanf("%d%d%d",&x,&y,&z);
            fac.push_back(point(x,y,z));
            sum+=z;
        }
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d",&x,&y);
            pku.push_back(point(x,y,0));
        }
        for(int i=0;i<m;++i)
        {
            for(int j=0;j<n;++j)
            {
                x=(pku[i].x-fac[j].x)*(pku[i].x-fac[j].x);
                y=(pku[i].y-fac[j].y)*(pku[i].y-fac[j].y);
                nodes.push_back(node(x+y,i,j));
            }
        }
        sort(nodes.begin(),nodes.end(),cmp);
        memset(mark,0,sizeof(mark));
        int j;
        for(xxx=0,j=0;xxx<nodes.size();++xxx)
        {
            if(mark[nodes[xxx].y]==0)
            {
                j++;
                mark[nodes[xxx].y]=1;
                if(j==n) break;
            }
        }
        high=sum;
        double ans=1000000007;
        for(;xxx<nodes.size();++xxx)
        {
            int l=sum/n;
            int r=high;
            if((double)l*sqrt(sqrt(nodes[xxx].dis))>ans)
                break;
            while(l<r)
            {
                int mid=(l+r)/2;
                if(judge(mid,0,n+m+1))
                    r=mid;
                else
                    l=mid+1;
            }
            high=min(high,r);
            ans=min(ans,high*sqrt(sqrt(nodes[xxx].dis)));
        }
        printf("%d\n",int(ans+0.5));
    }
}