IT民工
加油!

2012天津赛区现场赛的E题,刚才做模拟比赛的时候和安神讨论了很久,思路没理清。

大致题意是 给出N个点,让你选择性地建立加油站,在第i个点建立加油站的费用为2^i-1,要使自己能从1号点经过所有点回到原点,

点可以重复经过,加油费用不计,每次加油最多能跑的距离为D。输出的答案是2进制,由费用10进制转化过来就是在第i个点建立加

油站,答案从右往左数第i个值就为1。

第一步判断所有点都建立加油站能不能完成题目的要求,不能输出-1。

能完成要求的话,我们注意到建站费用是和点的编号有关的,比如第i个点建站的费用是等于前i-1个点都建站的费用+1,二进制的规律。

然后我们可以从后往前判断当前加油站能不能拆。

dist数组存从当前点到最近的加油站的距离,判断分两个方面:

如果当前点也有加油站,dist[i] <= D就可以;

如果当前点决定不建立加油站,那么dist[i]要小于D/2;

不符合要求就不能拆这个加油站。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <algorithm>
using std::queue;
using std::min;
const int MAXN = 130;
const int INF = 0x3f3f3f3f;

struct point
{
    int x, y;
}p[MAXN];

int n, d;
int g[MAXN][MAXN], dist[MAXN], sta[MAXN];
bool vis[MAXN];

int pf(int i)
{
    return i * i;
}

double distance(int i, int j)
{
    return sqrt((double)(pf(p[i].x - p[j].x) + pf(p[i].y - p[j].y)));
}

void ReadGraph()
{
    //让点号从0开始则每个点建立加油站的费用2^i
    for(int i = 0; i < n; i ++)
    {
        scanf("%d%d", &p[i].x, &p[i].y);
    }
    for(int i = 0; i < n; i ++)
        for(int j = 0; j < n; j ++)
        {
            g[i][j] = (int)ceil(distance(i, j));
        }
}

bool judge()
{
    queue<int> q;
    memset(vis, false, sizeof vis);
    for(int i = 0; i < n; i ++)
    {
        if(!sta[i]) dist[i] = INF;
        else dist[i] = 0;
    }
    vis[0] = true;
    dist[0] = 0;
    q.push(0);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        for(int i = 0; i < n; i ++)
        {
            if(!vis[i] && g[u][i] <= d)
            {
                dist[i] = min(dist[i], dist[u] + g[u][i]);
                if(sta[i])
                {
                    vis[i] = true;
                    q.push(i);
                }
            }

        }
    }
    for(int i = 0; i < n; i ++)
    {
        if(sta[i] && !vis[i])
            return false;
        else if(!sta[i] && dist[i] * 2 > d)
            return false;
    }
    return true;
}

void solve()
{
    for(int i = 0; i < n; i ++)
    {
        sta[i] = 1;
    }
    if(!judge())
    {
        puts("-1");
        return;
    }
    for(int i = n - 1; i >= 1; i --)
    {
        sta[i] = 0;
        if(judge()) continue;
        sta[i] = 1;
    }
    int cur = n - 1;
    while(!sta[cur])
        cur --;
    for( ; cur >= 0; cur --)
    {
        printf("%d", sta[cur]);
    }
    printf("\n");
}

int main()
{
    //freopen("test.in", "r", stdin);
    while(scanf("%d%d", &n, &d) != EOF)
    {
        ReadGraph();
        solve();
    }
    return 0;
}

 

 

 

posted on 2012-10-28 21:25  找回失去的  阅读(681)  评论(0编辑  收藏  举报