codeforces 677D

強行暴力水過……二維線段樹真的長,我實在是不想寫了.暴力1k左右,而二維線段樹5k……
題目大意
一個N*M的網格圖,每個格子有一把鑰匙,上面一個權值
要求從 1到 P按順序收集鑰匙,保證 P只有一把
問收集全部鑰匙的最短距離是多少
做法1:大概就是維護用縱列維護一個dis,用橫列維護一個dp,用vis維護他得到的鑰匙的序號,有才更新,感覺很巧妙.
狀態轉移方程
位置(r,c),更新dis[r][k]=min(dis[r][k],ans[r][c]+abs(c-k)),1<=k<=m。
ans[r][c]=min(ans[r][c],dis[k][c]+abs(c-r)),1<=k<=n
代碼

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair <int,int> mk;
int n,m,k,dp[305][305],vis[305][305],dis[305][305];
int t,len;
vector <mk>b[300*300+10];
void readdata()
{
    scanf("%d%d%d",&n,&m,&k);
    memset(dp,63,sizeof(dp));
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
            scanf("%d",&t);
            b[t].push_back(mk(i,j));
        }
        b[0].push_back(mk(1,1));
    for (int i=0;i<=k;i++)
    {
        len=b[i].size();
        for (int j=0;j<len;j++)
        {
            int r=b[i][j].first; int c=b[i][j].second;
            if (r==1&&c==1&&dp[r][c]==0) 
            {
                dp[r][c]=1000000000;
            } 

                for (t=1;t<=n;t++)
                {
                    if (vis[t][c]==i)
                    dp[r][c]=min(dp[r][c],dis[t][c]+abs(r-t));
                }
        }
        for (int j=0;j<len;j++)
        {
            int r=b[i][j].first; int c=b[i][j].second;
            for (int t=1;t<=m;t++)
            {
                if (vis[r][t]!=i+1)
                {   
                    vis[r][t]=i+1;
                    dis[r][t]=dp[r][c]+abs(c-t);
                }
                else 
                {
                    dis[r][t]=min(dis[r][t],dp[r][c]+abs(c-t));
                }
            }

        }
    }
    cout<<dp[b[k][0].first][b[k][0].second];
}
int main()
{
    readdata();
}

做法2
首先大家都應該能想的o(n^4)的暴力吧,我們只不過是用二維線段樹或二維樹狀數組優化成o(n^2*logn^2)而已,但代碼量大了不少.
狀態轉移方程
if(pi>=i&&pj>=j)dp[i][j]=min(dp[i][j],dp[pi][pj]+pi+pj-(i+j));
if(pi>=i&&pj<=j)dp[i][j]=min(dp[i][j],dp[pi][pj]+pi-pj-(i-j));
if(pi<=i&&pj>=j)dp[i][j]=min(dp[i][j],dp[pi][pj]+pj-pi-(j-i));
if(pi<=i&&pj<=j)dp[i][j]=min(dp[i][j],dp[pi][pj]-(pi+pj)+(i+j));
代碼就不貼了(我纔不會告訴你是因爲我沒調出來)
這道題方法很多,如暴力+bfs等,在此不再贅述(畢竟蒟蒻搞不懂)

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