hdu5506

来源:互联网 发布:银行贴现金额算法 编辑:程序博客网 时间:2024/05/16 01:09

GT and set

 
 Accepts: 35
 
 Submissions: 194
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
NN个集合,每个集合中有A_iAi个数。你要将这NN个集合划成LL个部分,使得每个部分的集合至少有一个共有的数。如果至少有一个解输出YESYES,否则输出NONO
输入描述
第一行一个数T表示数据组数。(TT\leq2020)对于每一组数据:第一行两个数NNLL。接下来NN行每行描述一个集合:第一个数A_iAi表示该集合的大小,之后xx个互不相同的整数表示该集合的元素。集合里的数字都是正整数且不大于300300.1\leq1NN\leq30301\leq1L\leq5L51\leq1A_iAi\leq10101 \leq L \leq N1LNhack时建议输出最后一行的行末回车;每一行的结尾不要输出空格。
输出描述
对于每组数据输出一行YESYESNONO
输入样例
22 11 11 23 23 1 2 33 4 5 63 2 5 6
输出样例
NOYES
Hint
对于第二个样例,有三个集合{1 2 3},{4 5 6},{2 5 6} 你要划成两个部分。有一种方案是把第二个和第三个集合划成一个部分,第一个在另一个部分。有一种方案是把第二个和第三个集合划成一个部分,第一个在另一个部分。 第二个和第三个集合的数字有一个交集{6},所以合法。还有一种划分方案就是把第一个和第三个集合划成一个部分,第二个在另一个部分。
这道题就是暴力。
已ac的代码。
#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#define N 310#define M 40#define L 20bool mark[M];int numat[N][M];int hasnum[M][L];int n;int allmark(){    for(int i=0;i<n;i++){        if(mark[i]==false){            return i;        }    }    return -1;}bool find(int l){    int temp=allmark();    if(temp==-1){        return true;    }    else{        if(l==0){            return false;        }        else{            for(int j=1;j<=hasnum[temp][0];j++){                int hasmark[N];                int tempnum=hasnum[temp][j];//不能定义为全局变量,因为在递归中,定义成全局变量后,会出错。                hasmark[0]=0;                for(int k=1;k<=numat[tempnum][0];k++){                    if(mark[numat[tempnum][k]]==false){                        mark[numat[tempnum][k]]=true;                        hasmark[++hasmark[0]]=numat[tempnum][k];                    }                }                if(find(l-1)){                    return true;                }                else{                    for(int k=1;k<=hasmark[0];k++){                        mark[hasmark[k]]=false;                    }                }            }            return false;        }    }}int main(){    int t;    int l;    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&l);        memset(numat,0,sizeof(numat));        memset(mark,false,sizeof(mark));        for(int i=0;i<n;i++){            scanf("%d",&hasnum[i][0]);            for(int j=1;j<=hasnum[i][0];j++){                int temp;                scanf("%d",&temp);                hasnum[i][j]=temp;                numat[temp][++numat[temp][0]]=i;            }        }        if(find(l)){            printf("YES\n");        }        else{            printf("NO\n");        }    }    return 0;}

 

感觉自己写的代码太复杂了,又从网上找了一份,学习一下思路,真的顺了很多。虽然思路简单的代码时间长了一点,但是让人写起来更省事。

ac的代码:

#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#define N 310#define M 40#define L 20bool vis[N];int numat[M][L];int n,l;void init(){    memset(vis,false,sizeof(vis));    scanf("%d%d",&n,&l);    for(int i=0;i<n;i++){        scanf("%d",&numat[i][0]);        for(int j=1;j<=numat[i][0];j++){            scanf("%d",&numat[i][j]);        }    }    return;}bool has(int u){    for(int i=1;i<=numat[u][0];i++){        if(vis[numat[u][i]]){            return true;        }    }    return false;}bool dfs(int u,int d){    if(u>=n){//集合存在0到n-1,而不是1到n,所以是>=,而不是>        return true;    }    else if(d>l){        return false;    }    else{        if(has(u)){            return dfs(u+1,d);        }        else{            for(int i=1;i<=numat[u][0];i++){                vis[numat[u][i]]=true;                if(dfs(u+1,d+1)){                    return true;                }                else{                    vis[numat[u][i]]=false;                }            }            return false;        }    }}int main(){    int t;    scanf("%d",&t);    while(t--){        init();        printf("%s\n",dfs(0,0)?"YES":"NO");    }    return 0;}



0 0
原创粉丝点击