absi2011's Blog & Daily Life.

全新的开始       我要省选翻盘       I wanna AK in 高考\化学       自此,生无可恋
[恢复状态] Gym 100273A [算法未证明 求神犇帮证]
[恢复状态] 学习waltz制作一个计划

[恢复状态] Gym 100273A - 另一种解

absi2011 posted @ Mar 29, 2016 08:10:54 AM in 刷题记录 with tags SPFA 网络流 小高考 费用流 CF Gym , 11960 阅读

感谢溪桥、吾愿提供另一种思路

再次感谢Jimmy.Carlson.Wang带我翻译题目

这一题除了上次瞎搞以外,还可以写网络流算法

或者说..最小费用最大流..

考虑任意一个苹果树和蚂蚁连一条距离为1,费用为dist(x,y)的边

s向苹果树连一条距离为1,费用为0的边;蚂蚁向t连一条距离为1,费用为0的边

这样建图跑一次可以保证总距离最小

总距离最小的话,不会有交叉(不然将它们换过来会更小)

所以..算法得证明正确性

*spfa写错了gg....调了半天

论正确写spfa的重要性....

代码:

#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<string>
#include<time.h>
#include<bitset>
#include<vector>
#include<memory>
#include<utility>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int inf=99999999;
int x[205],y[205];
double dists(int x,int y)
{
    return sqrt((double)(x*x+y*y));
}
struct edge
{
    int y;
    int weight;
    double cost;
    edge * next;
    edge * anti;
};
edge * li[205];
edge * new_edge()
{
    static edge a[100005];
    static int top=0;
    return &a[top++];
}
edge * inserts(int x,int y,int z,double w)
{
    edge * t=new_edge();
    t->y=y;
    t->weight=z;
    t->cost=w;
    t->next=li[x];
    li[x]=t;
    return t;
}
void insert_edge(int x,int y,int z,double w)
{
    edge * t1=inserts(x,y,z,w);
    edge * t2=inserts(y,x,0,-w);
    t1->anti=t2;
    t2->anti=t1;
}
double dist[1005];
bool visit[205];
int pre[205];
edge * path[205];
const double eps=1e-5;
double spfa(int s,int t)
{
    int i;
    for (i=0;i<205;i++)
    {
        dist[i]=inf;
    }
    dist[s]=0;
    memset(pre,-1,sizeof(pre));
    memset(path,0,sizeof(path));
    static int que[405];
    int front=0,rail=1;
    que[0]=s;
    memset(visit,0,sizeof(visit));
    visit[s]=true;
    for (;front!=rail;)
    {
        int now=que[front];
        front++;
        if (front==404) front=0;
        edge * x;
        for (x=li[now];x!=0;x=x->next)
        {
            if ((x->weight>0)&&(dist[now]+x->cost+eps<dist[x->y]))
            {
                dist[x->y]=dist[now]+x->cost;
                pre[x->y]=now;
                path[x->y]=x;
                if (!visit[x->y])
                {
                    visit[x->y]=true;
                    que[rail++]=x->y;
                    if (rail==404) rail=0;
                }
            }
        }
        visit[now]=false;
    }
    return dist[t];
}
void max_flow_min_cost(int s,int t)
{
    for (;spfa(s,t)!=inf;)
    {
        int now=t;
        int mins=inf;
        for (;now!=s;now=pre[now])
        {
            mins=min(mins,path[now]->weight);
        }
        now=t;
        for (;now!=s;now=pre[now])
        {
            path[now]->weight-=mins;
            path[now]->anti->weight+=mins;
        }
    }
}
int main()
{
    freopen("ants.in","r",stdin);
    freopen("ants.out","w",stdout);
    int n;
    scanf("%d",&n);
    int i;
    for (i=0;i<n+n;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
    }
    int s=n+n,t=n+n+1;
    for (i=0;i<n;i++)
    {
        insert_edge(s,i,1,0);
    }
    for (i=0;i<n;i++)
    {
        int j;
        for (j=n;j<n+n;j++)
        {
            insert_edge(i,j,1,dists(x[i]-x[j],y[i]-y[j]));
        }
    }
    for (i=0;i<n;i++)
    {
        insert_edge(i+n,t,1,0);
    }
    max_flow_min_cost(s,t);
    for (i=0;i<n;i++)
    {
        edge * t;
        for (t=li[i];t!=0;t=t->next)
        {
            if (t->weight==0)
            {
                printf("%d\n",t->y-n+1);
            }
        }
    }
    return 0;
}
Avatar_small
ジミ=カルソン 说:
Mar 29, 2016 03:38:59 PM

tag小高考什么鬼……
还有你这个前缀说实话可以去掉了……

Avatar_small
absi2011 说:
Mar 29, 2016 03:42:17 PM

小高考tag:
在小高考以前小高考相关的碎碎念以及某一篇辩证法的程序..
以及 小高考到高考期间因为化学历史两门科目考完以后的心理影响相关的一切(包括没心思做OI等状态)(所以要恢复到以前的状态,虽然似乎并不可能,所以每个文章都会有小高考tag)


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter