标签:ack 矩阵 算法 char 枚举 如何 输出 tor math
给定一个 \(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;
}
标签:ack 矩阵 算法 char 枚举 如何 输出 tor math
原文地址:https://www.cnblogs.com/1024-xzx/p/12941772.html