开始打比赛吧!!!
第一题:
A. 矩阵乘法
题目描述
这是一道模板题。
分别给定 n×p 和 p×m 的两个矩阵 A 和 B,求 A×B 。
输入格式
第一行三个正整数 n n n、p p p、m m m,表示矩阵的长宽。
之后的 n n n 行,每行 p p p 个整数,表示矩阵 A A A。
之后的 p p p 行,每行 m m m 个整数,表示矩阵 B B B。输出格式
输出 n 行,每行 m 个整数,表示矩阵 A×B,每个数模 10 ^ 9 + 7 输出。
样例
样例输入
3 4 5
-2 -8 -9 8
-10 0 6 -8
-10 -6 6 9
4 -7 5 -5 9
10 -2 -10 5 5
-3 -7 -3 8 -2
-6 7 7 3 -2样例输出
999999898 149 153 999999929 999999951
999999997 999999979 999999883 74 999999921
999999835 103 55 95 999999857数据范围与提示
1≤n,p,m≤500, −10^9≤A[i][j],B[i][j]≤ 10^9
这一道题就是一道数学题就可以了,代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn=500+5,inf=1000000000+7;
long long a[maxn][maxn],b[maxn][maxn];
int main(){
int n,p,m,i,j,k;
scanf("%d%d%d",&n,&p,&m);
for(i=1;i<=n;i++)
for(j=1;j<=p;j++)
scanf("%lld",&a[i][j]);
for(i=1;i<=p;i++)
for(j=1;j<=m;j++)
scanf("%lld",&b[i][j]);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
long long sum=0;
for(k=1;k<=p;k++){
sum+=a[i][k]*b[k][j];
sum%=inf;
}
if(j<m)
printf("%lld ",(sum+inf)%inf);
else
printf("%lld\n",(sum+inf)%inf);
}
return 0;
}
第二题:
B. 二分图匹配
题目描述
给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数
输入格式
第一行,n,m,e
第二至e+1行,每行两个正整数u,v,表示u,v有一条连边输出格式
共一行,二分图最大匹配
样例
输入样例#1:
1 1 1
1 1输出样例#1:
1
数据范围与提示
n,m≤1000
这一题具体思路就是我博客里之前写的:看这里
第三题:
C. 单源最短路
题目描述
给一个 n(1≤n≤2500) 个点 m(1≤m≤6200) 条边的无向图,求 s 到 t 的最短路。
输入格式
第一行四个由空格隔开的数整数n,m,s,t
之后的m行,每行三个正整数si,yi,wi(1<=wi<=10^9),表示从si到ti长度为wi的边输出格式
一个整数表示从 s s s 到 t t t 的最短路长度。数据保证至少存在一条道路。
样例
样例输入
7 11 5 4
2 4 2
1 4 3
7 2 2
3 4 3
5 7 5
7 3 3
6 1 1
6 3 4
2 4 3
5 6 3
7 2 1样例输出
7
思路:简单SPFA即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=62000+100;
const int INF=-2147483647;
struct Edge{
int to;
int val;
int next;
}edge[maxn*2];
int n,m,s,t,pos;
int head[maxn];
int dis[maxn];
void add_edge(int from,int to,int val){
edge[pos].to=to;
edge[pos].val=val;
edge[pos].next=head[from];
head[from]=pos++;
}
void spfa(int s){
int vis[maxn]={0};
memset(dis,INF,sizeof(dis));
vis[s]=true;
dis[s]=0;
queue<int>q;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=edge[i].next){
int to=edge[i].to;
if(dis[to]>dis[u]+edge[i].val){
dis[to]=dis[u]+edge[i].val;
if(!vis[to])
q.push(to);
}
}
}
}
int main(){
cin>>n>>m>>s>>t;
pos=0;
memset(dis,-1,sizeof(dis));
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
add_edge(a,b,c);
add_edge(b,a,c);
}
spfa(s);
cout<<dis[t];
return 0;
}
第四题:
D. 舞会
题目描述
某学校要召开一个舞会。现在已知在学校的所有 nnn 名学生中,有些学生曾经互相跳过舞。(跳过舞的两个学生一定是一个男生和一个女生)。现在要求被邀请的学生中的任何一对男生女生互相都不能跳过舞,求这个舞会最多能够邀请多少学生参加。
输入格式
输入的第一行是 n和 m 。其中 n 是可选的学生的总数,m 是已知的跳过舞的学生的对数。
然后有 m 行,分别包含两个非负整数,表示这两个编号的学生曾经跳过舞。其中,学生的编号从 0 号到 n−1 号。输出格式
只要求输出一行,其中包含一个数字,即能够邀请的最大的学生数。
样例
样例输入 1
8 6
0 2
2 3
3 5
1 4
1 6
3 1样例输出 1
5
样例输入 2
20 5
5 2
4 3
18 17
0 11
13 3样例输出 2
16
数据范围与提示
对于100% 的数据,n≤1000,m≤2000
代码:二分图最大匹配
#include <bits/stdc++.h>
using namespace std;
const int maxn=10000+10,Inf=0x7fffff;
int a[maxn][maxn],b[maxn];
int pp[maxn],n,k,x,y,m;
int ans;
bool dfs(int x){
for(int i=0;i<n;i++){
if (!b[i] && a[x][i]){
b[i]=1;
if(pp[i] == Inf|| dfs(pp[i])){
pp[x]=i;
pp[i]=x;
return true;
}
}
}
return false;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
a[x][y]=1;
a[y][x]=1;
}
for(int i=0;i<=n;i++)
pp[i]=Inf;
ans=n;
for(int i=0;i<n;i++){
if(pp[i]==Inf){
memset(b,0,sizeof(b));
if(dfs(i))
ans--;
}
}
printf("%d",ans);
return 0;
}