2018-10-14练习赛

开始打比赛吧!!!
第一题:

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

猜你喜欢

转载自blog.csdn.net/qq_42875611/article/details/83051146