#include<stdio.h>
#include<string.h>
#include<algorithm>
int e[110][110],culture[110][110],country[110],visit[110];//国家和文化的邻接矩阵
int N,K,M,S,T,learn[110],ans;
int judge(int x,int y)//判断学过的文化和x国家有冲突没有
{
if(culture[ country[y] ][ country[x] ])return 0;
if(culture[ country[T] ][ country[y] ])return 0;//如果终点国家排斥
for(int i=1;i<=learn[0];++i)
{
if(culture[learn[y]][country[i]])return 0;
}
return 1;
}
int dfs(int deep,int dis)
{
if(ans!=-1 && dis>=ans)return 0;//剪枝操作
if(deep==T)
{
ans=dis;//由于上一句的原因 那么能进来的肯定是比较小的距离
return 1;
}
for(int i=1;i<=N;++i)//遍历的邻边
{
if(deep==i)continue;
if(visit[i]==0 && judge(deep,i))//如果学过的文化和他没有冲突
{
visit[i]=1;
learn[0]++;
learn[learn[0]]=country[i];
dfs(i,dis+e[deep][i]);//递归
learn[0]--;
visit[i]=0;
}
}
return 1;
}
int main()
{
scanf("%d %d %d %d %d",&N,&K,&M,&S,&T);
for(int i=1;i<=N;++i)
scanf("%d",&country[i]);
for(int i=1;i<=K;++i)
for(int j=1;j<=K;++j)
scanf("%d",&culture[i][j]);
for(int i=1;i<=N;++i)
for(int j=1;j<=N;++j)
e[i][j]=9999;//对于题目来说 足够了
for(int i=1;i<=M;++i)
{
int u,v,d;
scanf("%d %d %d",&u,&v,&d);
if(!culture[country[v]][country[u]] && country[u]!=country[v])
e[u][v]=std::min(e[u][v],d);//这个顺序别搞反了,应该是你的国家不排斥我 我就可以过去,尽管 我排斥你
if(!culture[country[u]][country[v]] && country[u]!=country[v])
e[v][u]=std::min(e[v][u],d);
}
learn[0]=1;//存储已经学过的
learn[1]=country[S];
ans=-1;
memset(visit,0,sizeof(visit));
visit[S]=1;
dfs(S,0);
printf("%d\n",ans);
return 0;
}
32 网络警察
作者: Turbo 时间限制: 1S 章节: 基本练习(字符串)
问题描述 :
作为一名网络警察,你的任务是监视电子邮件,看其中是否有一些敏感的关键词。不过,有些狡猾的犯罪嫌疑人会改变某些单词的字母顺序,以逃避检查。请编写一个程序,发现这种调整过顺序的关键词。
输入说明 :
输入有两行,第一行是关键词列表,第二行是待检查的句子。
单词全部为小写,单词之间以一个空格分隔,每一行的单词个数不限
输出说明 :
输出为在该句子中所找到的经过顺序调整的关键词
按照在关键词列表中的先后顺序输出
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int cmp(const void *a,const void *b)
{
return *(char *)a - *(char *)b;
}
int main()
{
char key[2020][20],str[2020],c;
int i=0,j=0,flag[2020];//表示关键词是否出现过
while((c=getchar()) && c!='\n')
{
if(c==' '){key[i][j]='\0';j=0;i++;}
else key[i][j++]=c;
}
key[i][j]='\0';//录入关键词完毕
memset(flag,0,sizeof(flag));
while(scanf("%s",str)!=EOF)
{//灵光一闪 想到了对比两个单词的好方法
int len1=strlen(str);
qsort(str,len1,sizeof(str[0]),cmp);
for(int k=0;k<=i;k++)
{
int len2=strlen(key[k]);
if(len1==len2)//只有长度一样才可以比较
{
char temp[2020];
strcpy(temp,key[k]);
qsort(temp,len2,sizeof(temp[0]),cmp);
if(strcmp(temp,str)==0)flag[k]=1;
}
}
}
for(int coun=0,j=0;j<=i;j++)
if(flag[j]==1)printf(coun++==0?"%s":" %s",key[j]);
printf("\n");
return 0;
}
33 线段和点
作者: Turbo 时间限制: 1S 章节: 其它
问题描述 :
有n个点和m个区间,点和区间的端点全部是整数,对于点a和区间[b,c],若a>=b且a<=c,称点a满足区间[b,c]。
求最小的点的子集,使得所有区间都被满足。
输入说明 :
第一行两个整数n m
以下n行 每行一个整数,代表点的坐标
以下m行 每行两个整数,代表区间的范围
1<=n,m<=10000
0<=点和区间的坐标<=50000
输出说明 :
输出一行,最少的满足所有区间的点数,如无解输出-1。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct lineNode
{
int left,right;
}line;
int cmp(const void *a,const void *b)
{
line x=*(line *)a,y=*(line *)b;
if(x.left!=y.left)return x.left - y.left;
else return x.right - y.right;
}
int main()//将区间排序,然后遍历各段区间,对当前区间的各个坐标遍历,
//遍历时候的原则是尽量包含多的区间,且不能跑出前面的任何一个区间,如果跑出就停止遍历,记录下最大的点的位置
{
int m,n,ans=0,x,y,temp,dot[51001];//记录点,且把他能包含的最多段区间数记录到其中
line L[100001];
memset(L,0,sizeof(L));
memset(dot,0,sizeof(dot));
scanf("%d %d",&n,&m);
for(int i=0;i<n;++i){
scanf("%d",&temp);
dot[temp]=1;
}
for(int i=0;i<m;++i){
scanf("%d %d",&x,&y);
L[i].left=x;L[i].right=y;
}
qsort(L,m,sizeof(L[0]),cmp);
for(int i=0;i<m;++i){//遍历所有区间段
int maxnum=-1;
for(int j=L[i].left;j<=L[i].right;++j){//遍历所有的点
if(dot[j]){//若存在该点
dot[j]=1;//一定要重置为1.因为有可能他在上一组的运算中赋值很大
for(int k=i+1;k<m;k++){
if(j>= L[k].left && j<=L[k].right)dot[j]++;
else break;
}
if(maxnum<dot[j])maxnum=dot[j];
}
}
if(maxnum==-1){printf("-1\n");return 0;}
ans++;
i=i-1+maxnum;//若存在 则计数,且过滤掉已经包含的区间
}
printf("%d\n",ans);
return 0;
}
34 我们的征途是星辰大海
作者: Turbo 时间限制: 1S 章节: 模拟
问题描述 :
最新的火星探测机器人curiosity被困在了一个二维迷宫里,迷宫由一个个方格组成。
共有四种方格:
‘.’ 代表空地,curiosity可以穿过它
‘#’ 代表障碍物,不可穿越,不可停留
‘S’ 代表curiosity的起始位置
‘T’ 代表curiosity的目的地
NASA将会发送一系列的命令给curiosity,格式如下:“LRUD”分别代表向左,向右,向上,向下走一步。由于地球和火星之间最近时也有55000000km!所以我们必须提前判断这一系列的指令会让curiosity最终处在什么样的状态,请编程完成它。
输入说明 :
第一行是一个整数T,代表有几个测试样例
每个测试样例第一行是一个整数N(1<=N<=50))代表迷宫的大小(N*N)。随后的N行每行由N个字符串组成,代表迷宫。接下来的一行是一个整数Q,代表有多少次询问,接下来的Q行每行是一个仅由“LRUD”四个字母的组成的字符串,字符转长度小于1000.
输出说明 :
对于每个询问输出单独的一行:
“I get there!”:执行给出的命令后curiosity最终到达了终点。
“I have no idea!”:执行给出的命令后curiosity未能到达终点。
“I am dizzy!”:curiosity在执行命令的过程中撞到了障碍物。
“I am out!”:代表curiosity在执行命令的过程中走出了迷宫的边界。
#include<stdio.h>
#include<string.h>//简单模拟,直接写吧,把xy控制好就行
int T,N,Q;
char maze[100][100],quest[2020];
void operate(int x,int y)
{
int len=strlen(quest);
for(int i=0;i<len;++i)
{
if(quest[i]=='R')y++;
else if(quest[i]=='L')y--;
else if(quest[i]=='U')x--;
else if(quest[i]=='D')x++;
if(x>N || x<1 || y>N || y<1)
{
puts("I am out!");
return;
}
else if(maze[x][y]=='#')
{
puts("I am dizzy!");
return;
}
else if(maze[x][y]=='T')
{
puts("I get there!");
return;
}
}
puts("I have no idea!");
}
int main()
{
scanf("%d ",&T);
while(T--)
{
memset(maze,0,sizeof(maze));
int x=0,y=0;//起始位置的坐标
scanf("%d ",&N);
for(int i=1;i<=N;++i)
{
for(int j=1;j<=N;++j)
{
scanf("%c",&maze[i][j]);
if(maze[i][j]=='S'){x=i;y=j;}
}
getchar();
}
scanf("%d ",&Q);
for(int i=1;i<=Q;++i)
{
gets(quest);
operate(x,y);
}
}
return 0;
}
35 快速幂
作者: Turbo 时间限制: 1S 章节: 数学相关
问题描述 :
给定A, B, P,求(A^B) mod P。
输入说明 :
输入共一行。
第一行有三个数,A, B, P。
A, B为long long范围内的非负整数,P为int内的非负整数。
输出说明 :
输出共一行,表示所求。
#include<stdio.h>
int main()//快速幂有规律
{
long long a,b,ans;
int p;
scanf("%lld %lld %d",&a,&b,&p);
ans=1;
a%=p;
while(b>0)
{
if(b&1)ans=ans*a%p;//奇数要多乘一次
a=a*a%p;
b>>=1;//b除2
}
printf("%d\n",ans);
return 0;
}
36 日历
作者: Turbo 时间限制: 1S 章节: 基本练习(循环)
问题描述 :
已知2007年1月1日为星期一。设计一函数按照下述格式打印2007年以后(含)某年某月的日历,2007年以前的拒绝打印。为完成此函数,设计必要的辅助函数也是必要的。
输入说明 :
两个整数,表示年和月,以空格分隔
输出说明 :
按照范例输出
注意各个位置的空格数目,特别是每一行的末尾是否有空格。
#include<stdio.h>
int RunNian(int year)
{
return (year%400==0 ||(year%4==0 && year%100!=0));
}
int main()
{
int yy,mm,x,y,week=1;//0代表周日
int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
scanf("%d %d",&x,&y);
for(yy=2007;yy<x;++yy)
{
int days=365;
if(RunNian(yy))days++;
days=days%7;
week=(week+days)%7;
}//已经算得x年开头的星期几
if(RunNian(x))month[2]=29;
for(mm=1;mm<y;++mm)
{
week=(week+month[mm])%7;
}//算得mm月开头是星期几
printf("Calendar %d - %02d\n",yy,mm);//开始打印
printf("---------------------\n");
printf("Su Mo Tu We Th Fr Sa\n");
printf("---------------------\n");
int count=1;
for(int i=0;i<7;++i)//打印第一行
if(i<week)printf(" ");
else printf("%2d ",count++);
printf("\n");
week=0;
while(count<=month[mm])
{
printf("%2d ",count++);
if(++week%7==0)printf("\n");
}
if(week%7!=0)printf("\n");
printf("---------------------");
return 0;
}
37 分离度
作者: Turbo 时间限制: 1S 章节: 枚举
问题描述 :
在我们联系日益紧密的世界里,人们推测每个人和其他人的分离度不超过六(六度分离)。在这个问题里,你需要写一个程序来找出人们的关系网络中最大的分离度。
对于任意两个人,他们的分离度是联系两个人需要经过的最小的关系数。对于一个关系网络,最大的分离度是网络中任意两人的分离度的最大值。如果一个网络中有两个人没有通过关系链连接起来,这个网络是不连通的。
如下图所示,一个网络可以用一些连接两个人的对称关系来描述。一条线段表示两个人之间有联系。网络A描述了一个分离度最大值为2的网络,网络B没有连通。
输入说明 :
输入包含多组描述关系网络的数据,对于每组数据,第一行有两个数P,表示网络中人的数目,和R,关系的对数。接下来一行是R个关系。每个关系用两个字符串表示,代表网络中有关系的两个人的名字。每个名字是不同的,并且中间没有空格。因为一个人可能和多个人有联系,一个名字可能在一组数据中出现多次。
最后以一行两个0表示结束。
2<=P<=50,R>=1
输出说明 :
对于每个网络,输出网络中最大的分离度。如果这个网络是不连通的,输出DISCONNECTED。每一个网络输出后再输出一个回车。按照样例输出中的格式输出。
#include<stdio.h>
#include<iostream>//直接弗洛伊德吧
#include<string.h>
#include<map>
using namespace std;
map<string,int>people;
int edge[100][100];
int main()
{
int t=1,x,y;
char name1[100],name2[100];
while(scanf("%d %d",&x,&y)!=EOF && x+y)
{
people.clear();
memset(edge,0x3f3f3f3f,sizeof(edge));
int pos=1;
for(int i=0;i<y;++i)
{
scanf(" %s %s",name1,name2);
if(people[name1]==0)//如果是新成员
people[name1]=pos++;
if(people[name2]==0)//如果是新成员
people[name2]=pos++;
edge[people[name1]][people[name2]]=1;
edge[people[name2]][people[name1]]=1;
}
if(pos!=x+1)//人不够那么多 肯定是非连通的
{
printf("Network %d: DISCONNECTED\n\n",t++);
continue;
}
for(int k=1;k<=x;k++)
for(int i=1;i<=x;++i)
for(int j=1;j<=x;++j)//把自己到自己的情况去掉
if(i!=j && k!=i && k!=j && edge[i][k]+edge[k][j]<edge[i][j])edge[j][i]=edge[i][j]=edge[i][k]+edge[k][j];
int flag=1,dis=-1;
for(int i=1;i<=x && flag;++i)
for(int j=i+1;j<=x && flag;++j)
{
if(edge[i][j]==0x3f3f3f3f)flag=0;
if(edge[i][j]>dis)dis=edge[i][j];
}
if(!flag)printf("Network %d: DISCONNECTED\n\n",t++);
else printf("Network %d: %d\n\n",t++,dis);
}
return 0;
}
38 矩阵翻转
作者: Turbo 时间限制: 1S 章节: 枚举
问题描述 :
Ciel有一个NN的矩阵,每个格子里都有一个整数。
N是一个奇数,设X = (N+1)/2。Ciel每次都可以做这样的一次操作:他从矩阵选出一个XX的子矩阵,并将这个子矩阵中的所有整数都乘以-1。
现在问你经过一些操作之后,矩阵中所有数的和最大可以为多少。
输入说明 :
第一行为一个正整数N。
接下来N行每行有N个整数,表示初始矩阵中的数字。每个数的绝对值不超过1000。
1 <= N <= 33,且N为奇数。
输出说明 :
输出一个整数,表示操作后矩阵中所有数之和的最大值。
#include<stdio.h>
#include<stdlib.h>
#define max(a,b) a>b?a:b
int n,a[40][40],x,ans=-999999999;
void computing()
{
int maxnum=0,ta,tb;
for(int i=0;i<n;++i)maxnum+=a[x-1][i];
for(int i=0;i<x-1;++i)
{
ta=-999999999;
tb=a[i][x-1]+a[i+x][x-1];
for(int j=0;j<x-1;++j)tb+=abs(a[i][j]+a[i][j+x]+a[i+x][j]+a[i+x][j+x]);
ta=max(ta,tb);
tb=-1*(a[i][x-1]+a[i+x][x-1]);
for(int j=0;j<x-1;++j)tb+=abs( -1*a[i][j]+a[i][j+x]-a[i+x][j]+a[x+i][j+x] );
ta=max(ta,tb);
maxnum+=ta;
}
ans=max(maxnum,ans);
}
void solve()
{
for(int k=0;k<(1<<x-1);++k)//一定得是位运算 不然WA
{
for(int j=0;j<x-1;++j)
if((k&(1<<j))!=0)//位运算
{
for(int i=0;i<x;++i)
{
a[i][j]*=-1;
a[i][j+x]*=-1;
}
}
computing();
for(int j=0;j<x-1;++j)
if((k&(1<<j))!=0)//位运算
{
for(int i=0;i<x;++i)
{
a[i][j]*=-1;
a[i][j+x]*=-1;
}
}
}
}
int main()
{
scanf("%d",&n);
x=(n+1)/2;
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)scanf("%d",&a[i][j]);
solve();
printf("%d\n",ans);
return 0;
}
39 最大乘积
作者: Turbo 时间限制: 1S 章节: 深度优先搜索
问题描述 :
对于n个数,从中取出m个数,如何取使得这m个数的乘积最大呢?
输入说明 :
第一行一个数表示数据组数
每组输入数据共2行:
第1行给出总共的数字的个数n和要取的数的个数m,1<=n<=m<=15,
第2行依次给出这n个数,其中每个数字的范围满足:a[i]的绝对值小于等于4。
输出说明 :
每组数据输出1行,为最大的乘积。
#include<stdio.h>
int T,m,n,num[20],ans,flag[20];
void dfs(int sum,int deep)//把结果放到参数里面,省时一点
{
if(deep>m)return;//剪枝
if(deep==m)
{
ans=ans>sum?ans:sum;
return;
}
for(int i=0;i<n;++i)
{
if(flag[i]==0)
{
flag[i]=1;
dfs(sum*num[i],deep+1);
flag[i]=0;
}
}
}
int main()//排列组合的赶脚,无情TLE。加个剪枝
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=0;i<n;++i)
{
scanf("%d",&num[i]);
flag[i]=0;
}
ans=-999999999;
dfs(1,0);//从0开始 计数
printf("%d\n",ans);
}
return 0;
}
40 排列数
作者: Turbo 时间限制: 1S 章节: 深度优先搜索
问题描述 :
0、1、2三个数字的全排列有六种,按照字母序排列如下:
012、021、102、120、201、210
输入一个数n
求0~9十个数的全排列中的第n个(第1个为0123456789)。
输入说明 :
一行,包含一个整数n
输出说明 :
一行,包含一组10个数字的全排列
#include<stdio.h>
int n,num[20],flag[20],pos,ans;
void dfs(int sum,int deep)
{
if(deep==10)
{
ans++;
if(ans==n)
{
for(int i=0;i<=pos;++i)printf("%d",num[i]);
printf("\n");
}
return;
}
for(int i=0;i<10;++i)
{
if(flag[i]==0)
{
flag[i]=1;
num[++pos]=i;
dfs(10*sum+i,deep+1);
--pos;
flag[i]=0;
}
}
}
int main()//排列组合。开整
{
scanf("%d",&n);
pos=-1;
dfs(0,0);
return 0;
}