贪心(Elegant Construction,HDU 5813)

很容易想到按ai排序。

然后ai>i就不行。

然后就往前面连,保证恰好能到达ai个点。

看了官方题解就是往前a[i]个点都连边就好了。

由于有向无环,所以不可能到达比a[i]大的点,而小于等于a[i]的点我们又全都到达了。


我只想到了一个比较复杂的方法,算法错了,又改才对了。

就是讨论,如果a[i]=a[i-1]+1,那就直接连到i-1

如果a[i]=a[i-1],那就跟i-1一样连。

否则一定存在足够多的入度为0的点,我们不连他们,但连其他所有的点。

一开始有些地方想错了,就是想得不够清楚,所以WA了挺久。

算法实现有些麻烦。


希望自己以后能想明白,一方面降低出错的可能,另一方面降低代码复杂度。

感觉自己贪心的题目总是讨论得很复杂,主要原因就是没想彻底,然后就着急着写了。


代码

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
const int maxn = 1010;

vector<pii>vec;
int N;
int a[maxn];
int r[maxn];
int v[maxn];
int vis[maxn];
int viss[maxn];
vector<int>G[maxn];

int cmp(int i,int j)
{
    return a[i]<a[j];
}

void read()
{
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
    {
        scanf("%d",a+i);
        ++a[i];
        r[i]=i;
        v[i]=0;
        G[i].clear();
    }
}

void add(int u,int v)
{
    if(v)
    {
        G[u].push_back(v);
        vec.push_back(make_pair(r[u],r[v]));
    }
}

bool solve()
{
    vec.clear();
    read();
    sort(r+1,r+1+N,cmp);
    for(int i=1;i<=N;i++)
    {
        if(a[r[i]]>i) return false;
        if(a[r[i]]==a[r[i-1]])
            for(int j=0;j<(int)G[i-1].size();j++)
                add(i,G[i-1][j]);
        else if(a[r[i]]==a[r[i-1]]+1)
        {
            add(i,i-1);
            v[i-1]=0;
        }
        else
        {
            int num = i-a[r[i]];
            for(int j=1;j<i;j++) vis[j]=viss[j]=0;
            for(int j=1;j<i;j++)
            {
                if(!v[j]) viss[j]=1;
                else if(num)
                {
                    --num;
                    if(vis[a[j]]) continue;
                    vis[a[j]]=1;
                    for(int k=0;k<(int)G[j].size();k++)
                        viss[G[j][k]]=1;
                }
                else viss[j]=1;
            }
            for(int j=1;j<i;j++) if(viss[j]) add(i,j),v[j]=0;
        }
        v[i]=1;
    }
    return true;
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int t=1;t<=T;t++)
    {
        printf("Case #%d: ",t);
        if(solve())
        {
            puts("Yes");
            printf("%d\n",(int)vec.size());
            for(int i=0;i<(int)vec.size();i++)
                printf("%d %d\n",vec[i].first,vec[i].second);
        }
        else puts("No");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值