2015-2016 下半學期 第二週 訓練

1、hdu4081

題意:有n個城市,秦始皇要修用n-1條路把它們連起來,要求從任一點出發,都可以到達其它的任意點。秦始皇希望這所有n-1條路長度之和最短。然後徐福突然有冒出來,說是他有魔法,可以不用人力、財力就變出其中任意一條路出來。秦始皇希望徐福能把要修的n-1條路中最長的那條變出來,但是徐福希望能把要求的人力數量最多的那條變出來。對於每條路所需要的人力,是指這條路連接的兩個城市的人數之和。最終,秦始皇給出了一個公式,A/B,A是指要徐福用魔法變出的那條路所需人力, B是指除了徐福變出來的那條之外的所有n-2條路徑長度之和,選使得A/B值最大的那條。

題解:首先看到A/B這個式子,發現是沒法貪心的,因爲A和B是有聯繫的,那麼讓A/B儘可能大就只能讓B儘可能小。所以我們做一顆最小生成樹,然後枚舉樹上的邊,答案即爲MAX(cost[i]+cost[j]/MST-path[i][j])。

代碼:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long  long
#define db double
#define EPS 1e-15
#define inf 1e8

using namespace std;

double g[1010][1010],dis[1010],maxw[1010][1010];
bool vis[1010],used[1010][1010];
int pre[1010];
struct City{
    int x,y,w;
}city[1010];
db dist(City a,City b){
    return sqrt(abs((a.x-b.x)*(a.x-b.x))+abs((a.y-b.y)*(a.y-b.y)));
}
int main(){
    int T;
    scanf("%d",&T);
    while (T--){
        int n;
        scanf("%d",&n);
        for (int i=0;i<n;i++){
            scanf("%d%d%d",&city[i].x,&city[i].y,&city[i].w);
            for (int j=0;j<i;j++)
                g[i][j]=g[j][i]=dist(city[i],city[j]);
        }
        for (int i=0;i<n;i++){
            dis[i]=g[pre[i]=0][i];
            maxw[0][i]=0;
        }
        memset(vis,0,sizeof(vis));
        memset(used,0,sizeof(used));
        memset(maxw,0,sizeof(maxw));
        vis[0]=1;
        dis[n]=inf;
        db mst=0.0;
        for(int k=1;k<n;k++){
            int x=n;
            for (int i=0;i<n;i++)
                if (!vis[i] && dis[i]<dis[x]) x=i;
            for (int i=0;i<n;i++)
                if (vis[i]) maxw[i][x]=maxw[x][i]=max(dis[x],maxw[i][pre[x]]);
            mst+=dis[x];
            vis[x]=true;
            used[x][pre[x]]=used[pre[x]][x]=true;
            for (int i=0;i<n;i++)
                if (!vis[i] && g[x][i]<dis[i]) dis[i]=g[pre[i]=x][i];
        }
        db ans=0;
        for (int i=0;i<n;i++)
            for (int j=0;j<i;j++)
                ans=max(ans,(city[i].w+city[j].w)/(mst-maxw[i][j]));
        printf("%.2f\n",ans);
    }
    return 0;
}
2、poj1062

題意:中文題。

題解:這個題非常容易看成一張有向圖,人是圖中的節點,邊權爲需要附加的金錢,比如樣例,我們可以把它畫成下面的圖。


藍色路徑即爲最短路。

那麼剩下的等級問題,我們可以通過枚舉等級區間[l-m,m]~[m,l+m]中的點來解決,不在這個區間內的點在最短路的狀態被標記爲已訪問,這樣就不會出現錯誤。

代碼:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long  long
#define db double
#define EPS 1e-15
#define inf 1e8

using namespace std;

int dijkstra(int n, int mp[][101], int vis[]){
    int dis[101]={0},minn,t;
    for(int i=1;i<=n;i++) dis[i]=mp[0][i];
    while(1){
        minn=inf;
        for(int i=1;i<=n;i++)
            if ((vis[i]==0)&&(dis[i]<minn)){
                minn=dis[i];
                t=i;
            }
            if (minn==inf) break;
            vis[t]=1;
            for(int i=1;i<=n;i++)
            if((!vis[i])&&(mp[t][i]!=inf)&&(dis[i]>dis[t]+mp[t][i]))
                dis[i]=dis[t]+mp[t][i];
    }
    return dis[1];
}

int main(){
    int m,n,l[101],x,t,v,mp[101][101],vis[101],ans=inf;
    scanf("%d%d",&m,&n);
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++) mp[i][j]=inf;
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&mp[0][i],&l[i],&x);
        for(int j=0;j<x;j++){
            scanf("%d%d",&t,&v);
            mp[t][i]=v;
        }
    }
    l[0]=l[1];
    for (int i=l[1]-m;i<=l[1];i++){
        vis[0]=1;
        for(int j=1;j<=n;j++)
            if ((l[j]>=i)&&(l[j]<=(i+m))) vis[j]=0;
            else vis[j]=1;
            ans=min(ans,dijkstra(n,mp,vis));
    }
    printf("%d\n",ans);
    return 0;
}

3、hdu5137

題意:從2~n-1這幾個點中任意去掉一個點,使得從1到n的最短路徑最大,如果任意去掉一個點1~n無通路輸出Inf。

題解:枚舉刪除哪個點,每次在floyd數組中記錄一下最短路徑就好了。

代碼:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long  long
#define db double
#define EPS 1e-15
#define inf 1e8

using namespace std;

int n,m;
int d[40][40],g[40][40];
int solve(int x){
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            if (i==x || j==x) g[i][j]=inf;
            else g[i][j]=d[i][j];
    for (int k=1;k<=n;k++)
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                g[i][j]=min(g[i][j],g[i][k]+g[k][j]);

    return g[1][n];
}
int main(){
    while (scanf("%d%d",&n,&m) && (n!=0)){
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                d[i][j]=(i==j)?0:inf;
        for (int i=1;i<=m;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            d[u][v]=min(d[u][v],w);
            d[v][u]=d[u][v];
        }
        int ans=0;
        for (int i=2;i<n;i++)
            ans=max(ans,solve(i));
        if (ans==inf) puts("Inf");
        else printf("%d\n",ans);
    }
    return 0;
}

4、hdu5025

題意:反正就一個要你滿足各種條件然後到達終點的搜索題。

題解:感覺和上週那個搜索題差不多的思路,但是這次要用四維數組f[i][j][k][state]表示狀態 ,f[i][j][k][state]爲座標位置走到座標i,j時已經取得了k種鑰匙,當前蛇的狀態爲state,然後用個優先隊列維護個到達每個點用的步數。

代碼:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long  long
#define db double
#define EPS 1e-15
#define inf 1e8

using namespace std;

const int maxn=105;
const int dir[4][2]={{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
char mp[maxn][maxn];
int N, M;
int ok[maxn][maxn];
bool vis[maxn][maxn][10][1<<5];

struct Node{
    int x,y,d,key,kill;
    Node(int x, int y, int d, int key, int kill):x(x), y(y), d(d), key(key), kill(kill) {}
    bool operator < (const Node & rhs) const {
        return d > rhs.d;
    }
};
inline bool judge(int x, int y) {
    return x>=0 && x<N && y>=0 && y<N && mp[x][y]!='#';
}
int bfs(int x,int y){
    memset(vis,0,sizeof(vis));
    vis[x][y][0][0]=1;
    priority_queue<Node> q;
    q.push(Node(x,y,0,0,0));
    while (!q.empty()){
        Node tmp=q.top();
        q.pop();
        for (int i=0;i<4;i++){
            Node v(tmp.x+dir[i][0],tmp.y+dir[i][1],tmp.d+1,tmp.key,tmp.kill);
            if (!judge(v.x,v.y) || vis[v.x][v.y][v.key][v.kill])
                continue;
            vis[v.x][v.y][v.key][v.kill]=1;
            if (mp[v.x][v.y]=='S'){
                if(!(v.kill & (1<<ok[v.x][v.y]))){
                    v.d+=1;
                    v.kill|=(1<<ok[v.x][v.y]);
                }
                q.push(v);
            }
            else if (v.key+1==mp[v.x][v.y]-'0'){
                v.key+=1;
                q.push(v);
            }
            else if (mp[v.x][v.y]=='T' && v.key==M)
                return v.d;
            else q.push(v);
        }
    }
    return -1;
}
int main(){
    while (~scanf("%d%d",&N,&M),N!=0){
        int cnt=0,x,y;
        memset(ok,0,sizeof(ok));
        for (int i=0;i<N;i++){
            scanf("%s",mp[i]);
            for (int j=0;j<N;j++){
                if (mp[i][j]=='S') ok[i][j]=cnt++;
                if (mp[i][j]=='K') x=i,y=j;
            }
        }
        int b=bfs(x,y);
        if (b==-1) puts("impossible");
        else printf("%d\n",b);
    }
    return 0;
}


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