0
点赞
收藏
分享

微信扫一扫

东华进阶oj31-40

妖妖妈 2022-03-11 阅读 27

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#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;
}

举报

相关推荐

31-40oj

东华进阶oj41-50

东华OJ:班级排名

东华oj 1.huffman树

东华oj 2.回文数

东华大学 oj6 实数运算

LeetCode Hot100 31~40

0 条评论