$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 }