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
#include
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(i0;
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
#include
#include
#define maxn 2000+10
#define INF 1000000
using 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(ansprintf("%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
#include
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
#include
#include
#include
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
#include
#include
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+kkfor(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!