Noip 2015 senior ,The semi-finals,analysis (复赛题解)
来源:互联网 发布:吕宋岛 台风 知乎 编辑:程序博客网 时间:2024/06/11 11:20
My English teacher says that my English is not enough, so forgive me for working hard to analyse today in English.
Today I finished noip 2015 years problems of senior, quite a feeling.ok,sorry,I have exceeded my top of capacity,so I alter to Chinese.
好的,今天我很earnest很earnest做了这套题,并且很earnest很earnest的写了变量名,我是really想学好English的。
The first 题目,simulation,模拟!我们可以do it with enthusiasm. 我就不说blather了,直接附上代码,你们可以imitate my style of creating the name of variable。
#include<iostream>#include<cstdio>using namespace std;const int extend =40;inline int read(){ int data=0,w=1; char ch=0; while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar(); return data*w;}int data_number,x,y,i,judge_standard;int magic_square[extend][extend];void solve(){ while(i<data_number*data_number){ judge_standard = 0; magic_square [x] [y] = ++ i; if (x==1&&y!=data_number ) {judge_standard=1;x=data_number,y ++;} if (y == data_number && x != 1 && judge_standard == 0) { judge_standard=2;y=1;x --; } if (x == 1 && y == data_number && judge_standard == 0) { judge_standard=3;y=1;x=data_number;} if (judge_standard == 0 ){x --,y ++;} if (magic_square [x] [y]) switch ( judge_standard){ case 0 : x += 2,y --;break; case 1 : x = 1; break; case 2 : x ++; break; case 3 : x=2,y=data_number;break; } } }void lets_go_to_the_export(){ for (int j=1;j<= data_number;j++){ for ( int k = 1 ; k <= data_number ; k ++ ) printf ( "%d " , magic_square[j][k] ); putchar ( '\n' ); } }int main(){ freopen("magic.in","r",stdin); freopen("magic.out","w",stdout); data_number=read(); x=1,y=data_number/2+1,i=0; solve(); lets_go_to_the_export(); return 0;}
ok,the second 题目,读完题目过后,我们可以轻松distinguish这是一个ring。那么如何处理the smallest ring(草莽翻译),这是一个vital point。将题目translate一下,再形象的概括一下,最小环就相当于贪吃蛇,不断地elongate啊elongate,当chew到自己的body时,就结束。
那我们先一起来讲一讲最小环这个知识点吧。the smallest ring can be diveded 成两种class(类型),一种是有向的一种是无向的。先说有向吧,还是先说朴素算法。
令e(u,v)表示u和v之间的连边,再令min(u,v)表示,删除u和v之间的连边之后,u和v之间的最短路。最小环则是:min(u,v) + e(u,v),时间复杂度是EV2。其实都不用这种simple algorithm的,一般是用dijkstra或者是floyd。I recommend floyd,时间复杂度是O(n^3),不过如果大神会优先队列优化,那dijkstra不无不可。
https://vijos.org/p/1423,可以试试水,我来提供一个模板吧,O(∩_∩)O~。
#include <cstdio>#include <cstring>#include <algorithm>#define maxn 2000+10#define INF 1000000using namespace std;int n,m,a,b,c,dist[maxn][maxn],ans=INF,t[maxn];inline int read(){ int data=0,w=1; char ch=0; while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar(); return data*w;}int Min(int a,int b){ if(a>=b) return b; else return a;}int main(){ n=read(); m=read(); for(int i=1;i<=n;i++) t[i]=read(); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) dist[i][j]=dist[j][i]=INF; for(int i=1;i<=m;i++){ a=read();b=read();c=read(); dist[a][b]=Min(c+t[a],dist[a][b]); } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]); for(int i=2;i<=n;i++) ans=min(ans,dist[1][i]+dist[i][1]); if(ans<INF) printf("%d",ans); else puts("-1"); return 0;}
then,无向图的最小环的求法不可能和有向图的求法一样, 因为在有向图中i 到j 和 j 到i 算是一个环,但在无向图中不是一个环,
如果直接用flody算法将会出错, 有向图的环可以为2个顶点,而无向图的环至少要三个顶点; 所以为了求无向图的最小环, 我们采用的principle是: 枚举最大环中的连接点,更新环的权重; 比普通Floyd多出来的部分,主要use到的原理是当处理到k时,所有以1 到k - 1为中间结点的最短路径都已经确定,则这时候的环为(i到j(1 < i, j <= k - 1)的最短路径) + 边(i, k) + 边(k, j)遍历所有的i, j找到上述式子的最小值即位k下的最小代价环 。you can try try。
now,我们来solve the message problem,我就把my thinking写在代码里面了哦。
#include<iostream>#include<cstdio>using namespace std;const int extend =200010;/*不妨设每个点 i 有一条边连向点 t[i], 我们可以枚举从点 origination 出发, 然后一直走下去, 并且每经过一个点就标记这个点. 如果我们走到了一个已经标记了的点,此时有两种情况 1. 这个点在我们从 s 出发走出的这条路径上, 这说明我们找到了一个环, 那么用这个环的大小更新答案即可; 2. 否则, 我们已经处理过这个点了, 直接退出, 枚举下一个起点.*/inline int read(){ int data=0,w=1; char ch=0; while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar(); return data*w;}int Min(int a,int b){ if(a>=b) return b; else return a;}int is_used[extend],times[extend];int data_number,t[extend],ans = extend + 10000;void deep_First_Search(int origination){ int k = origination,auxliary = 0; while(true){ times[origination] = auxliary++; is_used[origination] = k; origination = t[origination]; if(is_used[origination] > 0){ if(is_used[origination] == k){ ans = Min(ans,auxliary - times[origination]); break; } else break; } }}void say_good_bye(int x){printf("%d",x);}int main(){ freopen("message.in","r",stdin); freopen("message.out","w",stdout); data_number=read(); for(int i=1;i<=data_number;i++) t[i]=read(); for(int i=1;i<=data_number;i++) if(is_used[i] == 0) deep_First_Search(i); say_good_bye(ans); return 0;}
大概就这样吧,图论is very essential。
最后一道题,我think:Facing the hopeless situation you should never say never, go ahead cheat for the score instead.
我只能cheat了,╮(╯▽╰)╭。全力去骗30分,就是当牌只有2,3,4张时。永远没有顺子的情况。先看代码吧。
#include<iostream>#include<iostream>#include<cstdio>#include<cstring>using namespace std;int data_number,n,Jack_card[20],receive1,receive2;inline int read(){ int data=0,w=1; char ch=0; while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar(); return data*w;}void readIn1(){ data_number=read(); n=read(); }void readIn2(){ for(int i=1;i<=n;i++){ receive1=read(); receive2=read(); if(receive1==0){ if(receive2==1) Jack_card[16]++; else Jack_card[17]++; } else if(receive1==1 || receive1==2) Jack_card[receive1+13]++; else Jack_card[receive1]++; }}void Memset(){for(int i=3;i<=17;i++) Jack_card[i]=0;}void print(int x){printf("%d\n",x);}void elaborator_cheat(){ if(n==2){ for(int i=3;i<=17;i++){ if(Jack_card[i]==2 ||(Jack_card[16]==1 && Jack_card[17]==1) ){ print(1); return ; } if(Jack_card[i]==1){ print(2); return ; } } } else if(n==3){ for(int i=3;i<=17;i++){ if(Jack_card[i]==3){ print(1); return ; } if(Jack_card[i]==2 ||(Jack_card[16]==1 && Jack_card[17]==1)){ print(2); return ; } } print(3); return ; } else if(n==4){ int num_of_couple=0; if(Jack_card[16]==1 && Jack_card[17]==1) num_of_couple++; for(int i=3;i<=17;i++){ if(Jack_card[i]==4 || Jack_card[i]==3){ print(1); return ; } if(Jack_card[i]==2) num_of_couple++; } if(num_of_couple==0){ print(4); return ; } if(num_of_couple==1){ print(3); return ; } if(num_of_couple==2){ print(2); return ; } }}int main(){ freopen("landlords.in","r",stdin); freopen("landlords.out","w",stdout); readIn1(); while(data_number--){ Memset(); readIn2(); elaborator_cheat(); } return 0;}
用尽毕生所学,枚举了2张,3张,4张的所有情况,I am very satisfied。
but now,我要学习一波正解,提高自己的代码及poker能力。
我research了一下big god的代码,都是优先搜索顺子,我思考了一下the reason,大概是有两个原因,一个是因为顺子最长,还有就是,只有顺子,会影响答案,所以搜索一下顺子的输出再剪枝。我的代码也许把你恶心到了,那下面这个代码,不是我写的了。想想吧。
#include<cstdio>#include<cstring>#include<climits>int t,n,x,y,a[5],b[14],maxx;int qiu(){ int tot=0; memset(a,0,sizeof(a)); for(int i=0;i<=13;i++) a[b[i]]++; while(a[4] && a[2]>1) a[4]--,a[2]-=2,tot++; while(a[4] && a[1]>1) a[4]--,a[1]-=2,tot++; while(a[4] && a[2]) a[4]--,a[2]--,tot++; while(a[3] && a[2]) a[3]--,a[2]--,tot++; while(a[3] && a[1]) a[3]--,a[1]--,tot++; return tot+a[1]+a[2]+a[3]+a[4];}void dfs(int u) //搜索顺子,二顺子,三顺子 { if(u>=maxx) return;int kk=qiu(); if(u+kk<maxx) maxx=u+kk; for(int i=2;i<=13;i++) { int j=i; while(b[j]>=3 && j<=13) j++; if(j-i>=2) for(int v=i+1;v<=j-1;v++) { for(int vk=i;vk<=v;vk++) b[vk]-=3; dfs(u+1); for(int vk=i;vk<=v;vk++) b[vk]+=3; } } for(int i=2;i<=13;i++) { int j=i; while(b[j]>=2 && j<=13) j++; if(j-i>=3) for(int v=i+2;v<=j-1;v++) { for(int vk=i;vk<=v;vk++) b[vk]-=2; dfs(u+1); for(int vk=i;vk<=v;vk++) b[vk]+=2; } } for(int i=2;i<=13;i++) { int j=i; while(b[j]>=1 && j<=13) j++; if(j-i>=5) for(int v=i+4;v<=j-1;v++) { for(int vk=i;vk<=v;vk++) b[vk]--; dfs(u+1); for(int vk=i;vk<=v;vk++) b[vk]++; } }}int main(){ scanf("%d%d",&t,&n); while(t--) { maxx=INT_MAX; memset(b,0,sizeof(b)); for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); if(x==1) x=13; else if(x) x--; b[x]++; } dfs(0); printf("%d\n",maxx); } return 0;}
。
at last,我talk about 我这次考试的情况吧,(还没做day2呢),
the first: expect 100,in fact 100.
the second:expect 100,in fact 100.
the third :expect 30,in fact 30.
我去学习一下dijkstra ,我没有recommend it 就是因为 I have not control it。So。。。。。。。。。
Good Bye!
- Noip 2015 senior ,The semi-finals,analysis (复赛题解)
- NOIP 2015 Senior 2
- NOIP 2015 Senior 3
- NOIP 2015 Senior 5
- NOIP 2015 Senior 4
- NOIP 2015 Senior 6
- 【蒻爆了的NOIP系列--普及组复赛】(1)NOIP2010普及组复赛题解
- 【蒻爆了的NOIP系列--普及组复赛】(2)NOIP2011普及组复赛题解
- 【蒻爆了的NOIP系列--普及组复赛】(4)NOIP2013普及组复赛题解
- 【蒻爆了的NOIP系列--普及组复赛】(5)NOIP2014普及组复赛题解
- 【蒻爆了的NOIP系列--普及组复赛】(6)NOIP2015普及组复赛题解
- 【蒻爆了的NOIP系列--普及组复赛】(3)NOIP2012普及组复赛题解
- 【蒻爆了的NOIP系列--普及组复赛】(7)NOIP2016普及组复赛题解
- NOIP-2016-普及组 复赛题解
- [NHZXOI2017]2016NOIP普及组复赛题解
- World Finals 2015简要题解
- NOIP 2009 Senior 1
- NOIP 2009 Senior 4
- GDI+
- JavaScript中几种常用的解决for循环中引用同一循环变量对象的方法
- 微信文件分享的那些坑
- 目标分割——基于目标轮廓
- Croc Champ 2012
- Noip 2015 senior ,The semi-finals,analysis (复赛题解)
- IMX6UL ARM 工控机
- 2017学习知识+学习计划
- JS如何去除指定字符串
- 387. First Unique Character in a String
- 三、Linux——Shell脚本语言
- 第六天-Java内部类
- 比较Activity与Fragment的生命周期
- Mac系统终端通过ssh连接CentOS