NOIP2015提高组题解 -DAY1
Day1 T1 - 神奇的幻方
描述:
幻方是一种很神奇的 N ∗ N 矩阵:它由数字 1,2,3, … … , N ∗ N 构成,且每行、每列及两条对角线上的数字之和都相同。
当 N 为奇数时,我们可以通过以下方法构建一个幻方: 首先将 1 写在第一行的中间。
之后,按如下方式从小到大依次填写每个数 K(K = 2,3, … , N ∗ N) :
1.若 (K − 1) 在第一行但不在最后一列,则将 K 填在最后一行, (K − 1) 所在列的右一列;
2.若 (K − 1) 在最后一列但不在第一行,则将 K 填在第一列,(K − 1) 所在行的上一行;
3.若 (K − 1) 在第一行最后一列,则将 K 填在 (K − 1) 的正下方;
4.若 (K − 1) 既不在第一行,也不在最后一列,如果 (K − 1) 的右上方还未填数, 则将 K填在(K − 1)的右上方,否则将 K 填在 (K − 1) 的正下方。
现给定 N,请按上述方法构造 N ∗ N 的幻方。
题解:
随便模拟一下就好了,题面还告诉你方法了呢。
代码:
#include <cstdio>
#include <iostream>
using namespace std;
int i,j,k,l,h,a[100][100]={0},n;
int main() {
scanf("%d",&n);
a[1][n/2+1]=1;
h=1;l=n/2+1;
for(i=2;i<=n*n;i++) {
if(h == 1 && l != n) { h=n;l++;a[h][l]=i;continue; }
if(h != 1 && l == n) { h--;l=1;a[h][l]=i;continue; }
if(h == 1 && l == n) { h++;a[h][l]=i;continue;}
if(a[h-1][l+1] != 0) { h++;a[h][l]=i;continue; }
h--;
l++;
a[h][l] = i;
}
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
printf("%d ",a[i][j]);printf("\n");
}
return 0;
}
Day1 T2 - 信息传递
描述:
有 n 个同学(编号为 1 到 n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为 Ti 的同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息, 但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
题解:
意思就是在图中找最小环,而且这是一个基环内向树,所以可以直接套模板;
也可以用Trajan找最小大于1的强连通分量;
还可以用饼茶鸡(并查集)、拓扑等等一些奇怪的方法;
我是用的dfs;(因为代码量最少,最容易想到啊!嘿嘿~)
代码:
#include <cstdio>
#include <iostream>
#define M 200002
using namespace std;
int n,t[M];
int vis[M]={0};
int mind=M,node;
inline int dfs(int i,int dis) {
vis[i] = 1;
if ( !vis[t[i]] )
dis = dfs(t[i],dis);
else node = t[i];
if (node == i)
mind = min(mind,dis);
return dis+1;
}
int main() {
scanf("%d",&n);
for (int i=1; i<=n; i++)
scanf("%d",&t[i]);
for (int i=1; i<=n; i++) {
node = 0;
if ( !vis[i] )
dfs(i,0);
}
printf("%d\n",mind+1);
}
Day1 T3 - 斗地主
描述:
牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、 方片的 A 到 K 加上大小王的共 54 张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。
需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。
具体规则如下:
题解:
额。。。。。。
这个题目做法也有蛮多,不多说;
可以想到不处理顺子的话最少出牌次数是一定的;
所以可以搜索顺子,其他的就好办了;
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int key[14] = {0,12,13,1,2,3,4,5,6,7,8,9,10,11};
int had[16];
template<typename T>
inline void read(T &x) {
char ch;
while (!isdigit((ch=getchar())));
for (x=ch-'0';isdigit((ch=getchar()));x=(x<<3)+(x<<1)+ch-'0');
ungetc(ch,stdin);
}
int n,Ti;
void init() {
memset(had,0,sizeof had);
for (int i=1,a,b;i<=n;i++) {
read(a); read(b);
if ( a == 0 ) had[13+b] ++;
else had[key[a]] ++;
}
}
int get() {
int count[5] = {0};
for (int i=1;i<=15;i++) {
if ( had[i] > 0 )
count[had[i]] ++;
}
int ans = 0;
bool flag = 0;
if ( had[14] == 1 && had[15] == 1 )
flag = 1;
while ( count[4] && count[2] >= 2 )
ans ++,count[4] --,count[2] -= 2;
while ( count[4] && count[1] >= 2 )
ans ++,count[4] --,count[1] -= 2;
while ( count[4] && count[2] )
ans ++,count[4] --,count[2] --;
while ( count[3] && count[2] )
ans ++,count[3] --,count[2] --;
while ( count[3] && count[1] )
ans ++,count[3] --,count[1] --;
if ( count[1] >= 2 && flag ) count[1] -= 1;
return ans + count[1] + count[2] + count[3] + count[4];
}
int Ans;
void dfs(int la,int ti) {
if ( la == 0 ) {
Ans = min(Ans,ti);
return ;
}
Ans = min(Ans,ti+get());
if ( ti >= Ans ) return;
if ( la >= 5 )
for (int p=3;p>=1;p--)
for (int i=1;i<=13;i++) {
int k = i;
while ( had[k] >= p && k < 13 ) k ++;
if ( (k-i) * p >= 5 ) {
for (int j=i;j<k;j++)
had[j] -= p;
for (int j=k-1;j>=i;j--) {
if( (j-i+1) * p >= 5 )
dfs(la-(j-i+1)*p,ti+1);
had[j] += p;
}
}
}
}
int main() {
read(Ti); read(n);
while ( Ti -- ) {
init();
Ans = n;
dfs(Ans,0);
printf("%d\n",Ans);
}
return 0;
}
注:就要NOIP2016了,写写题解来增强信心,加油咯~