洛谷P3104 [USACO14MAR]数朋友Counting Friends

题目描述

Farmer John's N cows (2 <= N <= 500) have joined the social network "MooBook".

Each cow has one or more friends with whom they interact on MooBook. Just for fun, Farmer John makes a list of the number of friends for each of his cows, but during the process of writing the list he becomes distracted, and he includes one extra number by mistake (so his list contains N+1 numbers, instead of N numbers as he intended).

Please help Farmer John figure out which numbers on his list could have been the erroneous extra number.

FJ又有n(1<=n<=500)头奶牛都有一个或一个以上的朋友。FJ记录每头牛的朋友数,但他傻不小心混入了一个错的数字,请找出。

输入输出格式

输入格式:

* Line 1: The integer N.

* Lines 2..2+N: Line i+1 contains the number of friends for one of FJ's cows, or possibly the extra erroneous number.

输出格式:

* Line 1: An integer K giving the number of entries in FJ's list that could be the extra number (or, K=0 means that there is no number on the list whose removal yields a feasible pairing of friends).

* Lines 2..1+K: Each line contains the index (1..N+1) within the input ordering of a number of FJ's list that could potentially be the extra number -- that is, a number that can be removed such that the remaining N numbers admit a feasible set of

friendships among the cows. These lines should be in sorted order.

输入输出样例

输入样例#1:  复制
4 
1 
2 
2 
1 
3 
输出样例#1:  复制
3 
1 
4 
5 

说明

Farmer John has 4 cows. Two cows have only 1 friend each, two cows have 2 friends each, and 1 cow has 3 friends (of course, one of these numbers is extra and does not belong on the list).

Removal of the first number in FJ's list (the number 1) gives a remaining list of 2,2,1,3, which does lead to a feasible friendship pairing -- for example, if we name the cows A..D, then the pairings (A,B), (A,C), (A,D), and (B,C) suffice, since A has 3 friends, B and C have 2 friends, and D has 1 friend. Similarly, removing the other "1" from FJ's list also works, and so does removing the "3" from FJ's list. Removal of either "2" from FJ's list does not work -- we can see this by the fact that the sum of the remaining numbers is odd, which clearly prohibits us from finding a feasible pairing.


题解:

orz。。。

这题的话没什么可以多解释的。 主要就是要敢于打暴力。

solution: 我们可以枚举哪个数字出错了。转为对剩下数字的判定性问题。 容易发现我们要判断的是一个图的合法性:给出出度判断能否构成。

我们可以设想,连边必然是先连出度大的,再连出度小的(如果你先连出度小的。你出度大的边的选择就少了。那么方案的构造就很容易失败了。)于是我们每次连完一个点之后就排一次序。直至整个序列为0.

但是有一个问题,这道题直接sort是最劣O(n3logn)的复杂度,十有八九要T

并且可以发现每次做完后原序列变成 0+有序+有序 ,所以可以归并优化时间复杂度到O(n3),稳过


代码(n3):

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int a[N],b[N],ans[N];
int t[N];
int n,tot;
bool com(int a,int b){return a>b;}//比较
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n+1;i++)scanf("%d",&a[i]);//读入
    for(int i=1;i<=n+1;i++){
        int k=0;
        for(int j=1;j<=n+1;j++)if(j!=i)b[++k]=a[j];
        sort(b+1,b+n+1,com);
        while(b[1]>0){//执行
            for(int j=2;j<=b[1]+1;j++)b[j]--;
            int l1=2,l2=b[1]+2;
            int r1=b[1]+1,r2=n;
            b[1]=0;k=0;
            while(l1<=r1&&l2<=r2){//归并
                if(b[l1]<=b[l2])t[++k]=b[l2],l2++;
                else t[++k]=b[l1],l1++;
            }
            while(l1<=r1)t[++k]=b[l1],l1++;
            while(l2<=r2)t[++k]=b[l2],l2++;
            for(int j=1;j<=n;j++)b[j]=t[j];
        }
        sort(b+1,b+n+1,com);
        if(b[n]==0)ans[++tot]=i;//判定
    }
    printf("%d\n",tot);
    for(int i=1;i<=tot;i++)//输出
        printf("%d\n",ans[i]);
    return 0;
}



代码(n3logn):

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=505;
int n,a[maxn];
inline void init(){
    scanf("%d",&n);
    for (int i=1;i<=n+1;i++){
        scanf("%d",&a[i]); 
    }
}
int ans,b[maxn],flag,q[maxn];
inline void solve(){
    for (int i=1;i<=n+1;i++){
        int tot=0;
        for (int j=1;j<=n+1;j++){
            if (j!=i) b[++tot]=a[j]; 
        }
        flag=1;
        for (int j=1;j<=n;j++){
            sort(b+1,b+1+n); int temp=n-1;
            while (b[temp]&&b[n]){
                b[n]--; b[temp]--; temp--;
            }
            if (b[n]) {
                flag=0; break;
            }
        }
        if (flag) q[++ans]=i;
    }
    printf("%d\n",ans);
    for (int i=1;i<=ans;i++) printf("%d\n",q[i]);
}
int main(){
    init();
    solve();
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/80863271