集合的包含
Problem Description
已知含n个元素的集合的子集A和B,用位串表示法判断是否有A⊆B。
Input
多组测试数据,每组测试数据第1行输入正整数n(1 <= n <= 100),表示集合元素个数,第2行输入位串表示法形式的集合A,第3行输入位串表示法形式的集合B。
Output
对于每组测试数据,若A⊆B则输出yes,反之则输出no。
Sample Input
10 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 10 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
Sample Output
yes no
#include<iostream>
using namespace std;
int f1[100];
int f2[100];
int main()
{
int n;
while(cin>>n)
{
for(int i = 0; i < n; i++)
cin>>f1[i];
for(int i = 0; i < n; i++)
cin>>f2[i];
int fl = 1;
for(int i = 0; i < n; i++)
if(f1[i] && !f2[i])
{
fl = 0;
break;
}
//如果f1中元素存在,而f2中不存在,退出循环
if(fl) cout<<"yes\n";
else cout<<"no\n";
}
}
偏序关系
Problem Description
给定有限集上二元关系的关系矩阵,确定这个关系是否是偏序关系。
Input
多组测试数据,对于每组测试数据,第1行输入正整数n(1 <= n <= 100),第2行至第n+1行输入n行n列的关系矩阵。
Output
对于每组测试数据,若为偏序关系,则输出yes,反之,则输出no。
Sample Input
4 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 4 1 0 0 1 0 1 0 0 0 0 1 0 1 0 0 1
Sample Output
yes no
Hint
偏序关系形式定义:设R是集合A上的一个二元关系,若R满足自反性、反对称性、传递性,则称R为A上的偏序关系
#include<stdio.h>
int f[200][200];
int main()
{
int n;
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &f[i][j]);
int fl = 1;
for(int i = 1; i <= n; i++)//自反
if(!f[i][i]) fl = 0;
//既矩阵对角线上元素全为1满足自反性
for(int i = 1; i <= n; i++)//反对称
for(int j = 1; j < i; j++)
if(f[i][j] && f[j][i]) fl = 0;
//对角线两侧元素不对称则满足反对称
for(int i = 1; i <= n; i++)//传递
for(int j = 1; j <= n; j++)
if(f[i][j])
for(int k = 1; k <= n; k++)
if(f[j][k] && !f[i][k]) fl = 0;
//选中元素的坐标,分别作为两行数,
//列数行若存在,则行数行也存在
//即满足传递关系
if(fl) printf("yes\n");
else printf("no\n");
}
}
1.1联结词真值运算
Problem Description
已知命题变元p和q的真值,求它们的合取式(p∧q)、析取式(p∨q)、蕴涵式(p→q)、等值式(A<=>B)、与非式(p↑q)、或非式(p↓q)的真值。
Input
多组输入,每组测试数据输入两个0或1的整数p和q,1表示真值为真,0表示真值为假
Output
每组测试数据单独占一行,以空格隔开的6个0或1的整数,分别为p和q的合取式(p∧q)、析取式(p∨q)、蕴涵式(p→q)、等值式(A<=>B)、与非式(p↑q)、或非式(p↓q)的真值。
Sample Input
0 0
Sample Output
0 0 1 1 1 1
#include<stdio.h>
int main()
{
int a, b;
while(~scanf("%d%d", &a, &b))
{
printf("%d %d %d %d %d %d\n",
a&&b, a||b, !a||(a&&b), a==b, !(a&&b), !(a||b));
//合取, 析取, 蕴涵, 等值, 与非, 或非
}
}
哪款赛车最佳?
Problem Description
四名专家对四款赛车进行评论。
专家A说:a号赛车是最好的。
专家B说:b号赛车是最好的。
专家C说:c号不是最佳赛车。
专家D说:专家B说错了。
事实上只有一款赛车最佳,且只有一名专家说对了,其他三人都说错了。请编程输出最佳车的编号,以及哪位专家所对了。
Input
多组测试数据,对于每组测试数据,第 1 行输入3个正整数,表示a、b 、c的编号,编号x范围(1 <= x <= 4),且编号互不相同。
Output
对于每组测试数据,输出正整数x和字符ch,表示最佳车的编号以及说对的专家的编号,详细格式请参考样例。
Sample Input
2 4 3
Sample Output
3 D
#include<stdio.h>
#include<stdlib.h>
int main()
{
int S1,S2,S3,S4,best,a,b,c;
while(~scanf("%d %d %d", &a, &b, &c))
{
for(best = 1; best <= 4; best++)
//每个编号都试一试
{
S1= (best==a);
S2= (best==b);
S3= (best!=c);
S4= !S2;
//按照语义赋值
if(S1+S2+S3+S4==1)
{
if(S1)
printf("%d %c\n",a,'A');
else if(S2)
printf("%d %c\n",b,'B');
else if (S3)
printf("c is'n best\n");
else if(S4)
printf("%d %c\n",c,'D');
break;
}
}
}
}
传递闭包
Problem Description
已知有n头牛,m次战斗关系,询问最终可以确定排名的牛的数量。
Input
多组测试数据,对于每组测试数据,第1行输入两个整数n(1 <= n <= 100)和m(0 <= m <= 4950),分别表示有n头牛和m次战斗关系,之后m行每行输入两个正整数x和y表示编号为x的牛可以战胜编号为y的牛,数据保证合法,询问可以确定排名的牛的数量。
Output
对于每组测试数据,输出整数ans,表示可以确定排名的牛的数量。
Sample Input
5 5 4 3 4 2 3 2 1 2 2 5
Sample Output
2
#include<stdio.h>
#include<string.h>
int f[101][101];
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
{
int x, y;
memset(f, 0, sizeof(f));
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &x, &y);
f[x][y] = 1;
}
for(int i = 1; i <= n; i++)//warshall算法
for(int j = 1; j <= n; j++)
if(f[j][i])//被选中元素存在
for(int k = 1; k <= n; k++)
f[j][k] = f[j][k]||f[i][k];
//列行数必须满足一定关系
// for(int i = 1; i <= m; i++)
// {
// for(int j = 1; j <= n; j++)
// printf("%d ", f[i][j]);
// printf("\n");
// }
int ans = 0;
for(int i = 1; i <= n; i++)
{
int c = 1;
for(int j = 1; j <= n; j++)
if(i != j && (f[i][j] || f[j][i])) c++;
if(c == n) ans++;
}
printf("%d\n", ans);
}
}
建图
Problem Description
编程使得程序可以接受一个图的点边作为输入,然后显示出这个图。
Input
多组测试数据,对于每组测试数据,第一行输入正整数n(1 <= n <= 1000)和m,之后m行输入正整数x、y,表示在点x和点y之间存在有向边相连。
Output
对于每组测试数据,输出图的关系矩阵。
Sample Input
4 5 1 1 2 2 2 4 3 3 4 4
Sample Output
1 0 0 0 0 1 0 1 0 0 1 0 0 0 0 1
#include<iostream>
#include<string.h>
using namespace std;
int f[10000][10000];
int main()
{
int n, m;
while(cin>>n>>m)
{
memset(f, 0, sizeof(f));
while(m--)
{
int x, y;
cin>>x>>y;
f[x][y] = 1;
}
for(int i = 1; i <= n; i++)
{
int fl = 1;
for(int j = 1; j <= n; j++)
{
if(fl) fl = 0;
else cout<<" ";
cout<<f[i][j];
}
cout<<endl;
}
}
}
指定长度路径数
Problem Description
题目给出一个有n个节点的有向图,求该有向图中长度为k的路径条数。方便起见,节点编号为1,2,…,n,用邻接矩阵表示该有向图。该有向图的节点数不少于2并且不超过500.
例如包含两个节点的有向图,图中有两条边1 → 2 ,2 → 1 。
长度为1的路径有两条:1 → 2 和 2 →1 ;
长度为2的路径有两条:1 → 2 → 1和2 → 1 → 2 ;
偷偷告诉你也无妨,其实这个图无论k取值多少 ( k > 0 ),长度为k的路径都是2条。
Input
多组输入,每组输入第一行是有向图中节点的数量即邻接矩阵的行列数n。接下来n行n列为该图的邻接矩阵。接下来一行是一个整数k.k小于30.
Output
输出一个整数,即为图中长度为k的路径的条数。
Sample Input
3 0 1 0 0 0 1 0 0 0 2
Sample Output
1
#include<iostream>
using namespace std;
int a[504][504];//原始矩阵
int b[504][504];//ans
int c[504][504];//辅助数组
int n;
void show()
{
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
cout<<b[i][j]<<" ";
cout<<endl;
}
}
int main()
{
while(cin>>n)
{
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
cin>>a[i][j];
b[i][j] = a[i][j];
}
int k;
cin>>k;
while(--k)//矩阵相乘
{
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
c[i][j] = 0;
for(int k = 0; k < n; k++)
c[i][j] += b[i][k]*a[k][j];
}
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
b[i][j] = c[i][j];
}
// show();
int ans = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
ans += b[i][j];
cout<<ans<<endl;
}
}
离散题目11
Problem Description
给定一个数学函数写一个程序来确定该函数是否是双射的
Input
多组输入。 第一行输入三个整数n,m,k,分别表示集合a中的元素个数,集合b中的元素个数,集合a到b的映射个数。 第二行输入n个数,代表集合a中的元素。 第三行输入m个数,代表集合b中的元素。接下来k行,每行两个数,代表集合a中的元素x和x在集合b中的像y。
Output
每组数据输出一行,若F为a到b的双射,输出"YES", 否则输出"NO"。
Sample Input
5 5 5 1 2 3 7 8 2 5 6 9 0 1 9 3 2 2 6 7 0 8 5
Sample Output
YES
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int f[10001];
int f1[2][10001];//[1]用于计数
int f2[10001];
int f3[10001];
int main()
{
int n, m, x, y, t, k;
while(~scanf("%d%d%d", &n, &m, &k))
{
memset(f, 0, sizeof(f));
memset(f1, 0, sizeof(f1));
memset(f2, 0, sizeof(f2));
memset(f3, 0, sizeof(f3));
for(int i = 0; i < n; i++)
{
scanf("%d", &t);
f1[0][t] = 1;
}
for(int i = 0; i < m; i++)
{
scanf("%d", &t);
f2[t] = 1;
}
int fl = 1;
for(int i = 0; i < k; i++)
{
scanf("%d%d", &x, &y);
f3[i] = y;
if(f1[0][x] && f2[y])
{
if(f1[1][x] && f[x] != y) fl = 0;//x多次出现且不满足单射
else //x第一次出现
{
f1[1][x]++;//x出现的次数
f[x] = y;//对应关系
}
}
else fl = 0; //x或y不在集合里
}
int c = 0;//是否满射
for(int i = 0; i < k; i++)
if(f2[f3[i]])
{
f2[f3[i]] = 0;
c++;
}
if(c != m) fl = 0;
if(fl) printf("YES\n");
else printf("NO\n");
}
}
离散题目12
Problem Description
给出两个集合,以及两个集合上的关系。判断该关系能不能构成函数
Input
多组输入。第一行数字表示集合A;第二行数字表示集合B;第三行一个数字N,表示关系的个数。以下N行,每行两个数字a b,用来描述关系a→b。0 < n < = 20000,集合A、B的大小不超过10000.
Output
每组数据输出一行,所给关系属于函数,输出’yes’ ,否则输出‘no’。
Sample Input
1 2 3 4 5 6 3 1 4 2 5 3 6 1 2 3 4 5 6 3 1 4 1 5 1 6
Sample Output
yes no
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
char a[400000];//不开大点就等着RE吧
char b[400000];
int x[20000];
int y[20000];
int cmp(const void *a, const void *b)
{
return *(int*)a > *(int *)b ? 1:-1;
}
int main()
{
while(gets(a))
{
gets(b);
//其实以上并没有什么卵用
int fl = 1;
int n;
cin>>n;
for(int i = 0; i < n; i++)
cin>>x[i]>>y[i];
qsort(x, n, sizeof(x[0]), cmp);
for(int i = 1; i < n; i++)//用桶排还RE,只能用老方法
{
if(x[i]- x[i-1] == 0)//x是否相等
{
fl = 0;
break;
}
}
if(fl) cout<<"yes\n";
else cout<<"no\n";
getchar();//我也不知道为什么也要这样,如果用endl刷新了缓存区,还是RE
//没有这玩意就等着RE吧
}
}
祝大家考试顺利