题解
今天大概是没带脑子…本来以为今天的题起码可以打230,但实际得分只有170…..orz。15年的题其实觉得还行。
第一题——神奇的幻方(magic)
【题目描述】
- 给出整数n按照规则求出矩阵。
规则:
首先将1写在第一行的中间。之后,按如下方式从小到大依次填写每个数
1.若 在第一行但不在最后一列,则将 填在最后一行, 所在列的右一列;
2.若在最后一列但不在第一行,则将 填第一列, 所在行的上一行;
3.若 在第一行最后一列,则将 的正下方;
4.若 既不在第一行,也不在最后一列,如果 的右上方还未填数,则将 填在 的右上方,否则将 填在 的正下方。
- 真的是一个无脑的简单模拟题….但首测只拿了70分…因为数组越界orz
- 详见代码。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
void fff(){
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
}
int map[1000][1000];
int l[1700],r[1700];
int nn;
int main(){
fff();
cin>>nn;
map[1][(nn+1)/2]=1;
l[1]=1;
r[1]=(nn+1)/2;
for (int i=2;i<=nn*nn;i++){
if(l[i-1]==1&&r[i-1]!=nn){
map[nn][r[i-1]+1]=i;
l[i]=nn;
r[i]=r[i-1]+1;
}else if(l[i-1]!=1&&r[i-1]==nn){
map[l[i-1]-1][1]=i;
l[i]=l[i-1]-1;
r[i]=1;
}else if(l[i-1]==1&&r[i-1]==nn){
map[l[i-1]+1][r[i-1]]=i;
l[i]=l[i-1]+1;
r[i]=r[i-1];
}else if(l[i-1]!=1&&r[i-1]!=nn){
if(!map[l[i-1]-1][r[i-1]+1]){
map[l[i-1]-1][r[i-1]+1]=i;
l[i]=l[i-1]-1;
r[i]=r[i-1]+1;
}else{
map[l[i-1]+1][r[i-1]]=i;
l[i]=l[i-1]+1;
r[i]=r[i-1];
}
}
}
for (int i=1;i<=nn;i++){
for (int j=1;j<=nn;j++){
printf("%d ",map[i][j]);
}
printf("\n");
}
return 0;
}
第二题——信息传递(message)
【题目描述】
- 给出n个点n条有向边,求图中最小强联通分量的点数。
- 因为n个点n条边。所以如果全联通的话,就只存在1个环,拿来一把dfs或者tarjan算法。就可以求出大小了。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
void fff(){
freopen("message.in","r",stdin);
freopen("message.out","w",stdout);
}
const int MAXN=200010;
int s[MAXN],t=0;
int n;
int a[MAXN];
int low[MAXN],dfn[MAXN],t_lorck=0,ans=MAXN*10;
void tarjan(int u){
low[u]=dfn[u]=++t_lorck;
if(!dfn[a[u]]){
s[++t]=a[u];
tarjan(a[u]);
low[u]=min(low[u],low[a[u]]);
}else{
low[u]=min(low[u],dfn[a[u]]);
}
if(low[u]==dfn[u]){
int sum=1;
while (s[t]!=u){
sum++;
t--;
}
if(sum>2) ans=min(ans,sum);
}
}
int main(){
fff();
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++){
if(!dfn[i]){
s[++t]=i;
tarjan(i);
}
}
cout<<ans;
return 0;
}
第三题——斗地主(landlords)
【题目描述】
- 如题吧,给出T组数据,每组n张牌,问最快几步打完所有牌。
- 规则见图。
扫描二维码关注公众号,回复:
2819760 查看本文章
- 其实这道题的数据在前三十分是比较水的。本来无脑可以拿三十分的。
- 但是我觉得还是打把dfs才对得起自己的良心。然后——超时了orz
- 其实也不算很烦这道题,思路比较好想:首先能够出顺子就出顺子,能够双排或者带掉就带掉,符合贪心的原则。但是由于可能出现两幅顺子重叠的情况:3 4 5 5 6 6 7 7 8 9 。所以就需要加上的dfs来进行更优的选择了。
- 代码不多,就200行orz
- 每次dfs之后都统计剩下的牌所能尽量打出的次数。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
void fff(){
freopen("landlords.in","r",stdin);
freopen("landlords.out","w",stdout);
}
int T,n;
int a[30],ans;
int sanpai(){
int cnt[5],temp[14],ret=0;
for (int i=1;i<=14;i++) cnt[a[i]]++;
for (int i=1;i<=14;i++) temp[i]=a[i];
if(cnt[4]&&(cnt[2]>2||cnt[3]>2)){//4-2
for (int i=1;i<=14;i++){
if(temp[i]==4){
for (int j=1;j<=14;j++){
if(j==i||temp[j]!=2) continue;
if(temp[i]<4) break;
for (int k=1;k<=14;k++){
if(k==i||k==j) continue;
if(temp[k]==2){
temp[i]-=4;
temp[j]-=2;
temp[k]-=2;
cnt[4]--;
ret++;
break;
}
}
}
}
}
}
if(cnt[4]&&(cnt[2]||cnt[3]||cnt[1])){
for (int i=1;i<=14;i++){
if(temp[i]==4){
for (int j=1;j<=14;j++){
if(i==j||temp[j]!=1) continue;
if(temp[i]!=4) break;
for (int k=1;k<=14;k++){
if(k==i||k==j) continue;
if(temp[k]==1){
temp[i]-=4;
temp[j]--;
temp[k]--;
cnt[4]--;
ret++;
break;
}
}
}
}
}
}
if(cnt[4]&&(cnt[2]||cnt[3])){
for (int i=1;i<=14;i++){
if(temp[i]==4){
for (int j=1;j<=14;j++){
if(j==i) continue;
if(temp[j]==2){
temp[i]-=4;
ret++;
temp[j]-=2;
cnt[4]--;
}
}
}
}
}
for (int i=1;i<=14;i++){
if(temp[i]>=3){
for (int j=1;j<=14;j++){
if(temp[j]==2){
temp[i]-=3;
temp[j]-=2;
ret++;
break;
}
if(temp[j]==1){
temp[i]-=3;
temp[j]-=1;
ret++;
break;
}
}
}
}
for (int i=1;i<=14;i++){
if(temp[i]==4) temp[i]-=4,ret++;
else if(temp[i]==3) temp[i]-=3,ret++;
else if(temp[i]==2) temp[i]-=2,ret++;
else if(temp[i])temp[i]-=1,ret++;
}
return ret;
}
void dfs(int step){
if(step>=ans){
return;
}
for (int i=1;i<=14;i++){
if(a[i]) break;
if(i==14) {
ans=step;
return;
}
}
int temp=sanpai();
if(temp+step<ans) ans=step+temp;
int cnt[5];
memset(cnt,0,sizeof(cnt));
for (int i=1;i<=14;i++) cnt[a[i]]++;
if(cnt[3]>=3){
for (int i=1;i<=10;i++){
for (int l=2;l<=12;l++){
for (int p=i;p<=l+i;p++){
if(a[p]<3||p>12) break;
else{
if(p==l+i){
for (int q=i;q<=p;q++) a[q]-=3;
cnt[3]-=(l+1);
dfs(step+1);
cnt[3]+=(l+1);
for (int q=i;q<=p;q++) a[q]+=3;
}
}
}
}
}
}
if(cnt[2]>=3){
for (int i=1;i<=10;i++){
for (int l=2;l<=12;l++){
for (int p=i;p<=l+i;p++){
if(a[p]<2||p>12) break;
else{
if(p==l+i){
for (int q=i;q<=p;q++) a[q]-=2;
cnt[2]-=(l+1);
dfs(step+1);
cnt[2]+=(l+1);
for (int q=i;q<=p;q++) a[q]+=2;
}
}
}
}
}
}
if(cnt[1]+cnt[2]+cnt[3]>5){
for (int i=1;i<=10;i++){
for (int l=4;l<=12;l++){
for (int p=i;p<=p+l;p++){
if(!a[p]||p>12) break;
else{
if(p==l+i){
for (int q=i;q<=p;q++) a[q]--;
dfs(step+1);
for (int q=i;q<=p;q++) a[q]++;
}
}
}
}
}
}
}
void init(){
memset(a,0,sizeof(a));
}
int main(){
fff();
scanf("%d%d",&T,&n);
while (T--){
init();
for (int i=1;i<=n;i++){
int t,s;
scanf("%d%d",&t,&s);
if(t>=3&&t<=13) a[t-2]++;
if(t==0) a[14]++;
if(t==1) a[12]++;
if(t==2) a[13]++;
}
ans=n;
dfs(0);
printf("%d\n",ans);
}
return 0;
}