1. 程式人生 > >每天一套題打卡|河南省第七屆ACM/ICPC

每天一套題打卡|河南省第七屆ACM/ICPC

node sid i++ ng- back rds while inside 相等

A 海島爭霸

題目:Q次詢問,他想知道從島嶼A 到島嶼B 有沒有行駛航線,若有的話,所經過的航線,危險程度最小可能是多少。

多源點最短路,用floyd
在松弛更新:g[i][k] < g[i][j] && g[k][j] < g[i][j]時,g[i][j] = max(g[i][k],g[k][j]);

#include<bits/stdc++.h>
using namespace std;

const int maxn = 510;
int n,m;
int q;
int g[maxn][maxn];

const int inf = 0x3f3f3f3f;
// 初始化 g 矩陣
void init() {
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (i == j) {
                g[i][j] = 0;
            } else {
                g[i][j] = inf;
            }
        }
    }    
}

// 插入一條帶權有向邊
void insert(int u, int v, int w) {
    g[u][v] = w;
}

// 核心代碼
void floyd() {
    for (int k = 1; k <= n; ++k) {
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                //這裏是本題的核心 松弛更新 
                if(g[i][k] < g[i][j] && g[k][j] < g[i][j]){
                    g[i][j] = max(g[i][k],g[k][j]);
                }
            }
        }
    }    
}



int main(){
    cin>>n>>m;
    init();
    for(int i=1;i<=m;i++){
        int a,b,v;
        cin>>a>>b>>v;
        if(v < g[a][b]){
            insert(a,b,v);
            insert(b,a,v);
        }
    }

    floyd();

    cin>>q;
    while(q--){
        int a,b;
        cin>>a>>b;
        if(g[a][b] == inf){
            cout<<-1<<endl;
        }else{
            cout<<g[a][b]<<endl;
        }
    }
    return 0;
} 

B 物資調度

1.dfs剪枝都能過。。
2.dp當然也可以
3.二進制枚舉wa了

#include<bits/stdc++.h>
using namespace std;

//AC

const int maxn = 110;
int t;
int n,m;
int a[maxn];
int vis[maxn];
int ans = 0;

//第k個數 當前值為sum 
void dfs(int k,int sum){
    if(sum > m) return;
    if(k==n+1){
        if(sum == m){
            ans++;
        }
        return;
    }
    //每個數有兩種選擇:用這個數 和 不用這個數 都dfs搜索一遍 
    dfs(k+1,sum);//不用這個數 
    if(sum + a[k]<=m){
        dfs(k+1,sum+a[k]);//用這個數 sum就需要加上當前這個數的值 
    }
}


int main(){
    cin>>t;
    while(t--){
        ans = 0;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        memset(vis,0,sizeof(vis));
        dfs(1,0);
        cout<<ans<<endl;
    }
    return 0;
} 

二進制枚舉做法

#include<bits/stdc++.h>
using namespace std;

//WA

const int maxn = 110;
int t;
int n,m;
int a[maxn];

int main(){
    cin>>t;
    while(t--){
        int ans = 0;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        //枚舉0 ~ 1<<n種狀態
        for(int i=0; i<(1<<n); i++){
            int sum = 0;
            for(int j=1;j<=n;j++){
                if(i & (1<<(j-1))){
                    sum += a[j];
                }
            }
            if(sum == m){
//              cout<<i<<endl;
                ans++;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
} 

*D 山區修路

技術分享圖片

我只能寫個2次dp的 暴力解法,但是這裏ai 有1e9這麽大,wa。
再補題。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 510;
int t;
int n;
int dp[maxn][maxn][2];
int a[maxn];
const int inf = 0x3f3f3f3f;

int main(){
    cin>>t;
    while(t--){
        cin>>n;
        int maxh = 0;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            if(a[i] > maxh) maxh = a[i];
        }
        memset(dp,inf,sizeof(dp));
        for(int i=0;i<=maxh;i++){
            dp[1][i][0] = abs(a[1] - i);
            dp[1][i][1] = abs(a[1] - i);
        }
        
        //從前推 低->高 
        for(int i=2;i<=n;i++){
            for(int j=0;j<=maxh;j++){
                for(int k=0;k<=j;k++){
                    dp[i][j][0] = min(dp[i][j][0],dp[i-1][k][0] + abs(a[i] - j));
                }
            }
        }

        //從前推 高->低 
        for(int i=2;i<=n;i++){
            for(int j=0;j<=maxh;j++){
                for(int k=j;k<=maxh;k++){
                    dp[i][j][1] = min(dp[i][j][1],dp[i-1][k][1] + abs(a[i] - j));
                }
            }
        }
        
        int ans = inf;
        for(int i=0;i<=maxh;i++){
            if(dp[n][i][1] < ans) ans = dp[n][i][1];
            if(dp[n][i][0] < ans) ans = dp[n][i][0]; 
        }
        cout<<ans<<endl;
    }
    
    return 0;
}

F Turing equation

題意:看樣例能猜到,the numbers being read backwards.

從後往前將字符串 轉成三個數,判斷和是否相等

#include<bits/stdc++.h>
using namespace std;

string s;

int main(){
    while(cin>>s && !(s[0] == '0' && s[1] == '+' && s[2] == '0' && s[3] == '=' && s[4] == '0' )){
        int len = s.length() - 1;
        int c = 0;
        int b = 0;
        int a = 0;

        int i = len;
        while(i>=0 && s[i] == '0') i--;
        while(i>=0 && s[i] >= '0' && s[i] <= '9'){
            c = c*10 + (s[i]- '0');
            i--;
            if(s[i] == '=') break;
        }
        if(i>=0 && s[i] == '=') i--;
        
        while(i>=0 && s[i] == '0') i--;
        while(i>=0 && s[i] >= '0' && s[i] <= '9'){
            b = b*10 + (s[i]- '0');
            i--;
            if(s[i] == '+') break;
        }
        
        if(i>=0 && s[i] == '+') i--;
        while(i>=0 && s[i] == '0') i--;
        while(i>=0 && s[i] >= '0' && s[i] <= '9'){
            a = a*10 + (s[i]- '0');
            i--;
        }
        if(a + b == c)
            cout<<"TRUE"<<endl;
        else
            cout<<"FALSE"<<endl;
    }
    return 0;
} 

H Rectangles

1.一眼遞推
2.LIS的dp

題目英文,細節比較多
The list can be created from rectangles in any order and in either orientation. //長寬可以交換

A rectangle fits inside another rectangle if one of its sides is strictly smaller than the other rectangle‘s and the remaining side is no larger.//給了樣例能懂

#include<bits/stdc++.h>
using namespace std;

const int maxn = 110;
int t,n;
int a[maxn];
struct node{
    int x;
    int y;
};

//ac

bool cmp(const node &p,const node &q){
    if(p.x == q.x) return p.y < q.y; 
    return p.x < q.x;
}

int main(){
    cin>>t;
    while(t--){
        cin>>n;
        node g[n+5];
        for(int i=1;i<=n;i++){
            int xi,yi;
            cin>>xi>>yi;
            if(xi < yi) swap(xi,yi); //這裏是註意點 
            g[i].x = xi;
            g[i].y = yi;
            a[i] = 1;
        }
        sort(g+1,g+n+1,cmp); //排序 
        int ans = 1;
        //遞推 
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){ 
                if((g[j].x > g[i].x && g[j].y > g[i].y) || (g[j].x > g[i].x && g[j].y == g[i].y) || (g[j].x == g[i].x && g[j].y > g[i].y) ){
                    a[j] = max(a[j],a[i]+1);
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(a[i] > ans) ans = a[i];
        }
        cout<<ans<<endl;
    }
    return 0;
} 

下面LIS最長上升子序列的寫法,也AC的

#include<bits/stdc++.h>
using namespace std;

//ac

/*
A rectangle fits inside another rectangle if one of its sides is strictly smaller than the other rectangle's 
and the remaining side is no larger.  
If two rectangles are identical they are considered not to fit into each other. 
For example, a 2*1 rectangle fits in a 2*2 rectangle, but not in another 2*1 rectangle.
容易看懂題意 
*/ 

//The list can be created from rectangles in any order and in either orientation.
//意思是長寬可以交換   想法:那麽我們在輸入數據的時候把小的給長 大的給寬就可以了 

const int maxn = 110;
int t,n;
int a[maxn];
struct node{
    int x;
    int y;
};

bool cmp(const node &p,const node &q){
    if(p.x == q.x) return p.y < q.y; 
    return p.x < q.x;
}

int main(){
    cin>>t;
    while(t--){
        cin>>n;
        node g[n+5];
        for(int i=1;i<=n;i++){
            int xi,yi;
            cin>>xi>>yi;
            if(xi < yi) swap(xi,yi);
            g[i].x = xi;
            g[i].y = yi;
            a[i] = 1;
        }
        sort(g+1,g+n+1,cmp);
        int ans = 0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){
                if((g[j].x < g[i].x && g[j].y < g[i].y) || (g[j].x < g[i].x && g[j].y == g[i].y) || (g[j].x == g[i].x && g[j].y < g[i].y) ){
                    a[i] = max(a[i],a[j]+1);
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(a[i] > ans) ans = a[i];
        }
        cout<<ans<<endl;
    }
    return 0;
} 

每天一套題打卡|河南省第七屆ACM/ICPC