$NOIP2010$ 题解报告

目录

•$Luogu\ P1514$ 引水入城$(\ √\ )$

•$Luogu\ P1525$ 关押罪犯$(\ √\ )$

•$Luogu\ P1540$ 机器翻译$(\ √\ )$

•$Luogu\ P1071$ 潜伏者$(\ √\ )$


 

$Luogu\ P1514$ 引水入城

题目传送门

这题挺简单的,搜索就能过,我用的$dfs$,大概讲一下思路

设$l[x][y],r[x][y]$记录经过$(x,y)$这一点向沙漠去的水利工程在沙漠中能到达的最左边的城市和最右边的城市。

初始值$l[n][y]=r[n][y]=y$,从第一行的点开始$dfs$,过程中更新$l,r$的值。

最后统计答案的时候,如果有沙漠中的城市没有水,就直接计算数量,否则用第一行的点的$l,r$来计算最少要建几个水利工程

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<queue>
 7 #define g() getchar()
 8 #define rg register
 9 #define go(i,a,b) for(rg int i=a;i<=b;i++)
10 #define back(i,a,b) for(rg int i=a;i>=b;i--)
11 #define db double
12 #define ll long long
13 #define il inline
14 #define pf printf
15 #define mem(a,b) memset(a,b,sizeof(a))
16 using namespace std;
17 int fr(){
18     int w=0,q=1;
19     char ch=g();
20     while(ch<'0'||ch>'9'){
21         if(ch=='-') q=-1;
22         ch=g();
23     }
24     while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g();
25     return w*q;
26 }
27 const int N=502;
28 int n,m,h[N][N],l[N][N],r[N][N];
29 int cx[4]={0,1,0,-1},cy[4]={1,0,-1,0};
30 bool vis[N][N];
31 il void work(rg int x,rg int y){
32     vis[x][y]=1;
33     go(i,0,3){
34         rg int X=x+cx[i],Y=y+cy[i];
35         if(X<1||X>n||Y<1||Y>m) continue;
36         if(h[X][Y]>=h[x][y]) continue;
37         if(!vis[X][Y]) work(X,Y);
38         l[x][y]=min(l[x][y],l[X][Y]);
39         r[x][y]=max(r[x][y],r[X][Y]);
40     }
41     return;
42 }
43 int main(){
44     //freopen("","r",stdin);
45     //freopen("","w",stdout);
46     n=fr();m=fr();
47     mem(l,0x3f);
48     go(i,1,m) l[n][i]=r[n][i]=i;
49     go(i,1,n) go(j,1,m) h[i][j]=fr();
50     go(i,1,m) if(!vis[1][i]) work(1,i);
51     rg int as=0;
52     go(i,1,m) if(!vis[n][i]) as++;
53     if(as){puts("0");pf("%d\n",as);return 0;}
54     int lft=1;
55     while(lft<=m){
56         rg int mxr=0;
57         go(i,1,m) if(l[1][i]<=lft) mxr=max(mxr,r[1][i]);
58         as++;lft=mxr+1;
59     }
60     puts("1");pf("%d\n",as);
61     return 0;
62 }
代码戳这里

 


 

$Luogu\ P1525$ 关押罪犯

题目传送门

用并查集做就可以了,贪心从大到小扫描每一条边,然后将这条边的两个端点加入不同的集合,如果当前这两个点已经在同一个集合中,则输出这条边的权值。

要注意一个就是我们记录每条边的两个端点互为敌人,本着敌人的敌人就是朋友的原则,将敌人的敌人与自己加入同一个集合

注意一下数据会有输出答案为$0$的情况。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define ri register int
 4 #define ll long long
 5 #define rl register ll
 6 #define go(i,a,b) for(ri i=a;i<=b;i++)
 7 #define back(i,a,b) for(ri i=a;i>=b;i--)
 8 #define g() getchar()
 9 #define il inline
10 #define pf printf
11 #define mem(a,b) memset(a,b,sizeof(a))
12 using namespace std;
13 il int fr(){
14     ri w=0,q=1;char ch=g();
15     while(ch<'0'||ch>'9'){if(ch=='-')q=-1;ch=g();}
16     while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=g();
17     return w*q;
18 }
19 const int N=2e4+2;
20 const int M=1e5+2;
21 int n,m,fa[N],ans,emy[N];
22 struct node{
23     int u,v,w;
24 }e[M];
25 il bool cmp(node x,node y){return x.w>y.w;}
26 il int find(ri x){return fa[x]==x?x:fa[x]=find(fa[x]);}
27 il void add(ri x,ri y){ri fx=find(x),fy=find(y);fa[fx]=fy;return;}
28 int main(){
29     //freopen(".in","r",stdin);
30     //freopen(".out","w",stdout);
31     n=fr();m=fr();
32     go(i,1,m)e[i]=(node){fr(),fr(),fr()};
33     sort(e+1,e+1+m,cmp);
34     go(i,1,n)fa[i]=i;
35     go(i,1,m){
36         ri u=e[i].u,v=e[i].v;
37         ri fu=find(u),fv=find(v);
38         if(fu==fv){ans=e[i].w;break;}
39         if(!emy[u])emy[u]=v;
40         else add(emy[u],v);
41         if(!emy[v])emy[v]=u;
42         else add(emy[v],u);
43     }
44     pf("%d\n",ans);
45     return 0;
46 }
代码戳这里

 


 

$Luogu\ P1540$ 机器翻译

题目传送门

大水题,无脑模拟即可

 1 #include<bits/stdc++.h>
 2 #define ri register int
 3 #define ll long long
 4 #define rl register ll
 5 #define go(i,a,b) for(ri i=a;i<=b;i++)
 6 #define back(i,a,b) for(ri i=a;i>=b;i--)
 7 #define g() getchar()
 8 #define il inline
 9 #define pf printf
10 #define mem(a,b) memset(a,b,sizeof(a))
11 using namespace std;
12 il int fr(){
13     ri w=0,q=1;char ch=g();
14     while(ch<'0'||ch>'9'){if(ch=='-')q=-1;ch=g();}
15     while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=g();
16     return w*q;
17 }
18 const int M=102;
19 int n,m,in[M],ans,num;
20 int main(){
21     //freopen(".in","r",stdin);
22     //freopen(".out","w",stdout);
23     m=fr();n=fr();
24     go(i,1,n){
25         ri x=fr();
26         bool yes=0;
27         go(j,0,min(num-1,m-1))if(in[j]==x){yes=1;break;}
28         if(yes)continue;
29         in[num%m]=x;num++;ans++;
30     }
31     pf("%d\n",ans);
32     return 0;
33 }
代码戳这里

 


 

$Luogu\ P1071$ 潜伏者

题目传送门

因为只有$4$中卡牌,且卡牌的数量范围较小,所以我们直接设$f[a][b][c][d]$表示分别使用了$a,b,c,d$张第$1,2,3,4$种卡牌的最大分数,然后暴力转移即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=352,M=42;
 4 int num[5],s[N];
 5 int f[M][M][M][M];
 6 int n,m;
 7 int main(){
 8     scanf("%d%d",&n,&m);
 9     for(int i=1;i<=n;i++)
10         scanf("%d",&s[i]);
11     int color;
12     for(int i=1;i<=m;i++)
13         scanf("%d",&color),num[color]++;
14     f[0][0][0][0]=s[1];
15     for(int a=0;a<=num[1];a++)
16         for(int b=0;b<=num[2];b++)
17             for(int c=0;c<=num[3];c++)
18                 for(int d=0;d<=num[4];d++){
19                     int now=1+a+b*2+c*3+d*4;
20                     if(a!=0)
21                         f[a][b][c][d]=max(f[a][b][c][d],f[a-1][b][c][d]+s[now]);
22                     if(b!=0)
23                         f[a][b][c][d]=max(f[a][b][c][d],f[a][b-1][c][d]+s[now]);
24                     if(c!=0)
25                         f[a][b][c][d]=max(f[a][b][c][d],f[a][b][c-1][d]+s[now]);
26                     if(d!=0)
27                         f[a][b][c][d]=max(f[a][b][c][d],f[a][b][c][d-1]+s[now]);
28                 }
29     printf("%d\n",f[num[1]][num[2]][num[3]][num[4]]);
30     return 0;
31 }
代码戳这里

 

posted @ 2019-10-26 20:15  小叽居biubiu  阅读(121)  评论(0编辑  收藏  举报