2012 Multi-University Training Contest 2

1001  排序+貪心(不會狀態DP)

題意:假設你的血是無限的但是攻擊力只有1,給出N個人的dps和hp,你每攻擊一個人,那麼這個人的血量減一,同時你的血量減少值爲所有活着的人的dps和,求最小花費多少血量可以把人全乾倒。

思路:按照dps/hp 排序 ,優先把dps/hp數值高的人幹掉。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct person {
    int dps;
    int hp;    
};
person p[35];
int cmp(person a , person b) {
    if((1.0*a.dps/a.hp) >= (1.0*b.dps/b.hp)) return 1;
    else if((1.0*a.dps/a.hp) == (1.0*b.dps/b.hp)) {
        if(a.hp <= b.hp) return 1;
        return 0;    
    }    
    return 0;
}
int main() {
    int N , i;
    while(cin>>N) {
        for(i = 0 ; i < N ; i ++) {
            cin>>p[i].dps>>p[i].hp;    
        }    
        sort(p , p + N , cmp);
        long long j , ans = 0;
        long long ss = 0;
        for(i = 0 ; i < N ; i ++) {
            ans += p[i].dps*p[i].hp;
            ss = 0;
            for(j = i+1 ; j < N ; j ++) {
                ss += p[j].dps;        
            }    
            ss *= p[i].hp;
            ans += ss;
        }
        cout<<ans<<endl;
    }    
}

1002  巧妙的枚舉

題意:給出一些點,找出一個點,使得其它點到這個點的曼哈頓距離最小。

平面上兩點間的 Manhattan 距離爲 |x1-x2| + |y1-y2|

思路:直接枚舉肯定TLE , 但是可以x方向和y方向分別計算。先把點按照x升序排序,要求出其它點到xi的距離∑|x - xi| ,pre[i] 代表小於等於xi的x的和,sumx[i]代表其它點到點i的x方向的曼哈頓距離。然後所有的sumx[i]都可以通過pre[i]推出,sumx[p[i].pos] = pre[n] - 2*pre[i] + (2*i-n)*p[i].x;  

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 100100;
struct point {
    ll x;
    ll y;    
    int pos;   //因爲排序後 點的原始位置被打亂 所以用pos記錄原始點的位置 
}p[maxn];
ll pre[maxn]; // 以xi爲最大的數 小於等於xi的累加和
ll sumx[maxn] , sumy[maxn]; //x 、y 方向上的和 
int cmp1(point a , point b) {
    return a.x < b.x;    
}
int cmp2(point a , point b) {
    return a.y < b.y;    
}
int main() {
    int T , n;
    cin>>T;
    while(T--) {
        cin>>n;
        int i;
        for(i = 1 ; i <= n ; i ++) {
            cin>>p[i].x>>p[i].y;
            p[i].pos = i;   
        }
        memset(sumx , 0 , sizeof(sumx));
        memset(sumy , 0 , sizeof(sumy));
        memset(pre , 0 , sizeof(pre));
        sort(&p[1] , &p[n+1] , cmp1);//x升序排序
        pre[1] = p[1].x;
        for(i = 2 ; i <= n ; i ++) 
        pre[i] = pre[i-1] + p[i].x;
        for(i = 1 ; i <= n ; i ++) {
            sumx[p[i].pos] = pre[n] - 2*pre[i] + (2*i-n)*p[i].x;  
            //cout<<"sumx = "<<sumx[p[i].pos]<<" "<<p[i].pos<<" "<<p[i].x<<" "<<p[i].y<<endl;  
        }
        //for(i = 1 ; i <= n ; i ++) 
        //cout<<sumx[i]<<" ";
        memset(pre , 0 , sizeof(pre));
        sort(&p[1] , &p[n+1] , cmp2);
        pre[1] = p[1].y;
        for(i = 2 ; i <= n ; i ++)
        pre[i] = pre[i-1] + p[i].y;
        for(i = 1 ; i <= n ; i ++) {
            sumy[p[i].pos] = pre[n] - 2*pre[i] + (2*i-n)*p[i].y;
        }
        ll ans;
        ans = sumx[1] + sumy[1];
        for(i = 1 ; i <= n ; i ++) {
            if(sumx[i] + sumy[i] < ans)
            ans = sumx[i] + sumy[i];    
        }
        cout<<ans<<endl;
    }
}

1006 Nim階梯博弈變型

詳解:xiuyang詳解

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main() {
    int i , N , k , a[1010];
    while(~scanf("%d%d",&N,&k)) {
        for(i = 0 ; i < N ; i ++)
        scanf("%d",&a[i]);
        if(k == 1) {
            printf("Alice\n");
            continue;
        }        
        int ans = 0;
        if(N%2==0) {
            for(i = 0 ; i < N - 1 ; i += 2) 
            ans = ans^(a[i+1] - a[i] - 1);    
        } 
        if(N%2==1) {
            if(k==2) a[0]--;
            ans = a[0];
            for(i = 1 ; i < N - 1 ; i += 2)
            ans = ans^(a[i+1] - a[i] - 1);    
        }
        if(!ans) printf("Bob\n");
        else printf("Alice\n");
    }    
}


1009 spfa

題意:就是求圖上s點到t點的最小power損失,鬆弛條件改改就行。

SPFA不熟,好多細節沒有注意到,跪了好久。。。 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define inf 0xfffffff
const int maxm = 2610000;
const int maxn = 51000;
struct edge {
    int v;
    double w;
    int nex;    
}e[maxm];
int head[maxn];
bool vis[maxn];
double d[maxn];
int k;
void add_edge(int a , int b , double w) {                 //加邊 
    e[k].v = b;
    e[k].w = w;
    e[k].nex = head[a];
    head[a] = k++; 
}
void spfa(int s , int m) {
    queue<int> Q;
    d[s] = 0;
    vis[s] = 1;
    Q.push(s);
    int t;
    while(!Q.empty()) {
        t = Q.front();
        Q.pop();
        vis[t] = 0;
        int j;
        for(j = head[t] ; j!=-1 ; j = e[j].nex) {
            int v = e[j].v;
            double w = e[j].w;
            if(d[v] > d[t] + (double)(m-d[t])*w) {
                d[v] = d[t] + (double)(m-d[t])*w;
                if(!vis[v]) { 
                    Q.push(v); 
                    vis[v] = 1;
                }
            }
        }    
    }    
}
int main() {
    int n;
    while(scanf("%d",&n)!=EOF) {
        int c , b;
        double w;
        memset(head , -1 , sizeof(head));
        k  = 1;
        for(int i = 1 ; i <= n ; i ++) {
            cin>>c;
            while(c--) {
                cin>>b>>w;
                w = (double)w/100.0;
                add_edge(i , b , w);   
            }
        }
        int s , t , m;
        scanf("%d%d%d",&s,&t,&m);
        for(int i = 0 ; i <= n ; i ++) d[i] = inf;
        memset(vis , 0 , sizeof(vis));
        spfa(s , m);
        if(d[t]!=inf)
        printf("%.2lf\n",d[t]);
        else
        printf("IMPOSSIBLE\n");
    }    
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章