1. 程式人生 > >2018-10-14練習賽

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