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