本场链接:https://codeforces.ml/contest/1517
B. Morning Jogging-贪心
Problem
给出n+1个点,编号从0-n,相邻两个点i,i+1之间有m条边,有m个人从0号点出发到n号点,每条边只能被一个人走,一个人的疲惫程度时这个人所走边权值的最小值。问m个人疲惫程度和最小时多少。
Solution
先对每个点连接的m条边由小到大排序,每次取同一列中最小的值,找到其所在行,对于其它行就取这行的最大值。为了方便,每一行用两个指针指向第一列和最后一列,也就相当于一个指向了最小值,一个指向了最大值。
用样例1来看:
Code
#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
const int N = 2e6+7;
const int mod = 1e9+7;
const ll ds = 1e15;
const double eps = 1e-8;
using namespace std;
int a[105][105],ans[105][105],jz[105][2];
void solve(){
int n,m;
cin >> n >> m;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin >> a[i][j];
}
jz[i][0] = 1;
jz[i][1] = m;
sort(a[i]+1,a[i]+m+1);
}
for(int i = 1; i <= m; i++){
int mmin = a[1][jz[1][0]],xb = 1;
for(int j = 1; j <= n; j++){
if(a[j][jz[j][0]] < mmin){
mmin = a[j][jz[j][0]];
xb = j;
}
}
for(int j = 1; j <= n; j++){
if(j == xb){
ans[j][i] = a[j][jz[j][0]];
jz[j][0]++;
}
else ans[j][i] = a[j][jz[j][1]],jz[j][1]--;
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cout << ans[i][j] << " ";
}
puts("");
}
}
int main(){
int t;
cin >> t;
while(t--)
solve();
//system("pause");
return 0;
}
C. Fillomino 2-DFS
Problem
给出一个n*n的矩阵,对角线上放1-n的一个排列,然后要将对角线及以下部分分块,每一块内的数字必须相同,并且块的大小要和数字相同。问能否构造出来。
Solution
首先容易想到的是一定能够构造出来的,然后对于对角线上的每个数为起点进行dfs,优先向左填,如果不能填再向下填,还不行就向右填。
Code
#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
const int N = 2e6+7;
const int mod = 1e9+7;
const ll ds = 1e15;
const double eps = 1e-8;
using namespace std;
int a[505][505],n;
void dfs(int r,int c,int num){
//cout << r << " " << c << endl;
if(num >= a[r][c])
return;
if(r <= 0 || r > n || c <= 0 || c > r)
return;
if(!a[r][c-1] && c >= 2){
a[r][c-1] = a[r][c];
dfs(r,c-1,num+1);
}
else if(!a[r+1][c] && r < n){
a[r+1][c] = a[r][c];
dfs(r+1,c,num+1);
}
else if(!a[r][c+1] && c < r && r <= n){
a[r][c+1] = a[r][c];
dfs(r,c+1,num+1);
}
}
void solve(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i][i];
}
for(int i = 1; i <= n; i++){
dfs(i,i,1);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= i; j++){
cout << a[i][j] << " ";
}
puts("");
}
}
int main(){
// int t;
// cin >> t;
// while(t--)
solve();
//system("pause");
return 0;
}
D. Explorer Space-DP
Problem
给出n*m的矩阵,每个点和它右边相邻的点有一条无向边,和它下面相邻的点有一条无向边,对于每一个点,求从这个点走k步还回到这个点的最短距离,注意走过的点还可以走。
Solution
如果k为奇数的话是一定不能回到最初位置的,所有直接看k为偶数的情况。
首先我们先找到k/2步能够走的最短距离是多少,然后原路返回就是走k步的最短距离,因为走完k/2步不可能还有其它更短的距离道达最初位置,因为从最初位置走k/2已经是最短距离了,这就矛盾了呀!
Code
#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
const int N = 2e6+7;
const int mod = 1e9+7;
const ll ds = 1e15;
const double eps = 1e-8;
using namespace std;
ll ans[505][505],dp[505][505][50],a[505][505][5];
void solve(){
int n,m,k;
cin >> n >> m >> k;
//memset(dp,0x3f3f3f3f,sizeof(dp));
for(int i = 1; i <= n; i++){
for(int j = 1; j < m; j++){
dp[i][j][0] = 0;
cin >> a[i][j][0];
a[i][j+1][1] = a[i][j][0];
}
}
for(int i = 1; i < n; i++){
for(int j = 1; j <= m; j++){
dp[i][j][0] = 0;
cin >> a[i][j][2];
a[i+1][j][3] = a[i][j][2];
}
}
if(k&1) {
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cout << "-1 ";
}
puts("");
}
return;
}
k /= 2;
for(int i = 1; i <= k; i++){
for(int j = 1; j <= n; j++){
for(int l = 1; l <= m; l++){
dp[j][l][i] = 0x3f3f3f3f3f;
if(j != 1){
dp[j][l][i] = min(dp[j][l][i],dp[j-1][l][i-1]+a[j][l][3]);
}
if(l != 1){
dp[j][l][i] = min(dp[j][l][i],dp[j][l-1][i-1]+a[j][l][1]);
}
if(j != n){
dp[j][l][i] = min(dp[j][l][i],dp[j+1][l][i-1]+a[j][l][2]);
}
if(l != m){
dp[j][l][i] = min(dp[j][l][i],dp[j][l+1][i-1]+a[j][l][0]);
}
}
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cout << 2*dp[i][j][k] << " ";
}
puts("");
}
}
int main(){
// int t;
// cin >> t;
// while(t--)
solve();
//system("pause");
return 0;
}