【NOIp】NOIp2010

NOIp2010

T1 机器翻译

标签:模拟,STL

两种做法,同一本质

1.依题意模拟

code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,x,ans,l,r,a[1005],b[1005];
 4 int main()
 5 {
 6     cin>>m>>n;
 7     l=0;r=0;
 8     for (int i=1;i<=n;i++)
 9     {
10          scanf("%d",&x);
11          if (a[x]==0) 
12          {
13               ans++;
14               r++;b[r]=x;a[x]=1;
15               if (r>m) {l++;a[b[l]]=0;}
16          }
17      }
18      cout<<ans;
19      return 0;
20 }
T1.1

早期代码

2.发现题意就是个队列,STL水一波

code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4   inline int read(){
 5     int x=0,f=1;char s=getchar();
 6     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
 7     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
 8     return f*x;
 9   }
10   int n,m,vis[1005],ans;
11   queue<int>q;
12   int main(){
13     m=read();n=read();
14     for(int i=1;i<=n;i++){
15       int x=read();
16       if(vis[x])continue;
17       if(q.size()>=m){
18         int k=q.front();q.pop();
19         vis[k]=0;
20       }
21       q.push(x);vis[x]=1;ans++;
22     }
23     printf("%d",ans);
24     return 0;
25   }
26 }
27 int main(){
28   gengyf::main();
29   return 0;
30 }
T1.2

T2 乌龟棋

标签:dp

用每种卡片的数量表示状态

f[i][j][k][l]表示用第一种卡片i张,第二种j张,第三种k张,第四种l张时得到的分数

用卡片张数就能够算出当前位置

转移方程为

f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l]+a[pos]) (pos=1+i+2*j+3*k+4*l) pos是当前位置,a[i]表示i位置的分数

j,k,l同理

code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4     inline int read(){
 5         int x=0,f=1;char s=getchar();
 6         while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
 7         while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
 8         return x*f;
 9     }
10     int n,m,a[400],tmp[5],st;
11     int f[50][50][50][50];
12     int main() {
13         n=read();m=read();
14         for(int i=1;i<=n;i++){
15             a[i]=read();
16         }
17         for(int i=1;i<=m;i++){
18             int x;
19             x=read();
20             tmp[x]++;
21         }
22         for(int i=0;i<=tmp[1];i++)
23             for(int j=0;j<=tmp[2];j++)
24                 for(int k=0;k<=tmp[3];k++)
25                     for(int l=0;l<=tmp[4];l++){
26                         st=1+i+j*2+k*3+l*4;
27                         if(i)f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l]+a[st]);
28                         if(j)f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k][l]+a[st]);
29                         if(k)f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k-1][l]+a[st]);
30                         if(l)f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k][l-1]+a[st]);
31                     }
32         printf("%d",f[tmp[1]][tmp[2]][tmp[3]][tmp[4]]+a[1]);
33         return 0;
34     }
35 }
36 int main(){
37     gengyf::main();
38     return 0;
39 }
T2

T3 关押罪犯

标签:图论,数据结构

两种做法

1.排序后并查集维护犯人之间的怨气值,依据"敌人的敌人是朋友"原则分配监狱

如果不可避免将两个互为敌人的罪犯分到一个监狱,就输出怨气值

code

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 struct node {int x,y,z;};
 5 node f[100005];
 6 int n,m,a[20005],b[20005],i;
 7 inline bool cmp(node a,node b)
 8 {
 9     return a.z>b.z;
10 }
11 inline int find(int x)
12 {
13     if(a[x]==x) return x;
14     a[x]=find(a[x]);
15     return a[x];
16 }
17 inline void merge(int x,int y)
18 {
19     x=find(a[x]);
20     y=find(a[y]);
21     a[x]=y;
22 }
23 inline bool check(int x,int y)
24 {
25     x=find(x);
26     y=find(y);
27     if(x==y) return true;
28     return false;
29 }
30 int main()
31 {
32     scanf("%d%d",&n,&m);
33     for(i=1;i<=n;i++) a[i]=i;
34     for(i=1;i<=m;i++)
35         scanf("%d%d%d",&f[i].x,&f[i].y,&f[i].z);
36     sort(f+1,f+m+1,cmp);
37     for(i=1;i<=m+1;i++)
38     {
39         if(check(f[i].x,f[i].y)) {printf("%d",f[i].z);break;}
40         else
41         {
42             if(!b[f[i].x]) b[f[i].x]=f[i].y;
43                 else {merge(b[f[i].x],f[i].y);}
44             if(!b[f[i].y]) b[f[i].y]=f[i].x;
45                 else {merge(b[f[i].y],f[i].x);}
46         }
47     }
48     return 0;
49 }
T3.1

早期代码

2.二分图

二分怨气值后黑白染色判断能否形成二分图,如果能就更新答案 

code(有注释)

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4   inline int read(){
 5     int x=0,f=1;char s=getchar();
 6     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
 7     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
 8     return f*x;
 9   }
10   const int maxm=100010;
11   const int maxn=20010;
12   int n,m;
13   struct edge{
14     int nxt,to,w;
15   }e[maxm*2];
16   int head[maxn],cnt,l=0,r,color[maxn];
17   void add(int from,int to,int w){
18     e[++cnt].to=to;e[cnt].nxt=head[from];
19     e[cnt].w=w;head[from]=cnt;
20   }
21   bool check(int x){
22     queue<int>q;
23     memset(color,0,sizeof(color));
24     for(int i=1;i<=n;i++){
25       if(color[i])continue;
26       q.push(i);color[i]=1;
27       while(!q.empty()){
28         int k=q.front();q.pop();
29         for(int j=head[k];j;j=e[j].nxt){
30           if(e[j].w>=x){
31             if(!color[e[j].to]){//没染过色
32               color[e[j].to]=(color[k]==1?2:1);
33               q.push(e[j].to);
34               //涂上相反颜色入队
35             }
36             else if(color[e[j].to]==color[k])return 0;
37             //如果出现矛盾直接返回(不为二分图)
38           }
39         }
40       }
41     }
42     return 1;
43   }
44   int main(){
45     n=read();m=read();
46     for(int i=1;i<=m;i++){
47       int u,v,w;
48       u=read();v=read();w=read();
49       r=max(r,w);
50       add(u,v,w);add(v,u,w);
51     }
52     r++;
53     while(l+1<r){
54       int mid=(l+r)>>1;
55       if(check(mid)){//染色法判断二分图如果可行就缩小范围
56         r=mid;
57       }
58       else l=mid;
59     }
60     printf("%d",l);
61     return 0;
62   }
63 }
64 int main(){
65   gengyf::main();
66   return 0;
67 }
T3.2

T4 引水入城

标签:搜索

把第一排每个点都dfs一遍,找到这个点能覆盖的底层点,看能不能覆盖完

如果不能直接返回

如果能覆盖完,可以发现每一个第一排的点覆盖的都是底层的一段区间,于是问题转化为最小区间覆盖,贪心或dp都可解

code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4     const int inf=1e9+7;
 5     inline int read(){
 6         int x=0,f=1;char s=getchar();
 7         while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
 8         while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
 9         return f*x;
10     }
11     int a[550][550],v[550][550],vl[550],f[505];
12     int block,cnt,ans,n,m;
13     struct node{
14         int l,r;
15     }c[10005];
16     void dfs(int x,int y,int k){
17         v[x][y]=1;
18         if(x==n){
19             vl[y]=1;
20             c[k].l=min(c[k].l,y);
21             c[k].r=max(c[k].r,y);
22         }
23         if(a[x][y]>a[x+1][y]&&!v[x+1][y]&&x!=n)dfs(x+1,y,k);
24         if(a[x][y]>a[x-1][y]&&!v[x-1][y]&&x!=1)dfs(x-1,y,k);
25         if(a[x][y]>a[x][y-1]&&!v[x][y-1]&&y!=1)dfs(x,y-1,k);
26         if(a[x][y]>a[x][y+1]&&!v[x][y+1]&&y!=m)dfs(x,y+1,k);
27     }
28     int main(){
29         n=read();m=read();
30         for(int i=1;i<=n;i++)
31             for(int j=1;j<=m;j++){
32                 a[i][j]=read();
33             }
34         for(int i=1;i<=m;i++){
35             c[i].l=f[i]=inf;
36         }
37         f[0]=0;
38         for(int i=1;i<=m;i++){
39             if(a[1][i-1]<=a[1][i]&&a[1][i+1]<=a[1][i]){
40                 dfs(1,i,i);
41             }
42             memset(v,0,sizeof(v));
43         }
44         for(int i=1;i<=m;i++){
45             if(!vl[i])block++;
46         }
47         if(block){
48             printf("0
%d",block);
49             return 0;
50         }
51         for(int i=1;i<=m;i++)
52             for(int j=1;j<=m;j++){
53                 if(i>=c[j].l&&i<=c[j].r){
54                     f[i]=min(f[i],f[c[j].l-1]+1);
55                 }
56             }
57         printf("1
%d",f[m]);
58         return 0;
59     }
60 }
61 int main(){
62     gengyf::main();
63     return 0;
64 }
T4

总结: 思维难度逐渐上升,有点NOIp的样子了,题目的多解也能够带来很大启发

原文地址:https://www.cnblogs.com/gengyf/p/11508171.html