Cave Escape

题意:

给定一个 \(n∗m\) 的格子矩阵,其中有一个格子是起点,一个格子是终点。从起点开始移动,每次能移动到有相邻边的格子中,每个格子都有一个权值 \(v\),若从点 \((x,y)\) 移动到点 \((i,j)\),且\((i,j)\) 点未被访问过,则可以获得 \(V_{(x,y)}*V_{(i,j)}\) 的收益,若移动到终点,可以选择先不出去,继续在图上乱走,问如何可以使得走出终点后获得得收益最大?(只需要输出最大收益即可)

传送门

分析:

思路:不管起点在哪里,因为权值都为正数,我们要让收益最大,肯定尽量每个点都访问一遍,然后才是最大的值,所以我们可以直接建图,然后跑一遍生成树(最大),因为要让每个点访问一次。按一般的最小生成树的算法会超时。

正解:存图是把权值作为索引,然后从大到小依次枚举。

代码:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int N=1010;
const int M=1e4+5;
const int maxn=2e6+10;
int pic[N][N];
int x[maxn];
vector<P>dis[M];
int n,m,sr,sc,tr,tc,p,a,b,c;
int fa[maxn];
void read(int &d)
{
    d=0;
    int f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        d=(d<<3)+(d<<1)+ch-'0';
        ch=getchar();
    }
    d*=f;
}
int Find(int d)
{
    if(d!=fa[d])
        return fa[d]=Find(fa[d]);
    else
        return d;
}
ll solve(int tol)
{
    ll ans=0;
    int cnt=0;
    for(int i=1e4;i>=0;i--)
    {
        for(int j=0;j<dis[i].size();j++)
        {
            P t=dis[i][j];
            int u=t.first;
            int v=t.second;
            int fu=Find(u);
            int fv=Find(v);
            if(fu!=fv)
            {
                fa[fu]=fv;
                ans+=i;
                cnt++;
            }
            if(cnt==n*m-1)
                return ans;
        }
    }
}
int main()
{
    int t,cas=0;
    read(t);
    while(t--)
    {
        for(int i=0;i<=1e4;i++)
            dis[i].clear();
        read(n),read(m),read(sr),read(sc),read(tr),read(tc);
        read(x[1]),read(x[2]),read(a),read(b),read(c),read(p);
        for(int i=3;i<=n*m;i++)
            x[i]=(a*x[i-1]+b*x[i-2]+c)%p;
        int tol=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                int t=(i-1)*m+j,tt;
                pic[i][j]=x[t];
                fa[t]=t;
                if(i-1>=1)
                {
                    tt=(i-2)*m+j;
                    dis[pic[i][j]*pic[i-1][j]].pb(make_pair(t,tt));
                }
                if(j-1>=1)
                {
                    tt=(i-1)*m+j-1;
                    dis[pic[i][j]*pic[i][j-1]].pb(make_pair(t,tt));
                }
            }
        }
        printf("Case #%d: %lld\n",++cas,solve(tol));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/1024-xzx/p/12941772.html