您的位置:首页 > 其它

51nod 1693 水群(神奇的最短路!)

2017-08-21 10:12 393 查看
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1693

题意:



思路:

这个思路真是神了。。

对于每个点$i$,它需要和$i-1$连一条边,代表退格操作,权值为1,但是对于复制粘贴操作就比较麻烦了,因为它可以复制之后粘贴多次,这样的话,就可以从$i$转换成$i*k$,k就是操作的次数,但是k的取值太多了,我们肯定是需要优化的(毕竟就0.4秒的时间。。),首先k的取值可能限制在质数之内,为什么可以把合数去掉呢,因为它完全可以由多次代价低的操作组合在一起实现等价的效果,代价总和还是一样的。进一步可以发现k的范围大致就是{2,3,5,7,11,13}这几个数之间(这我也不太清楚为什么,我觉得是如果一下子粘贴那么多次,那它完全可以先粘贴后然后复制再粘贴,这样的话代价会更小一点),还有就是退格操作不会连续超过4次(这我也不太清楚,我觉得是如果退格次数多了,那完全可以在复制前先退格然后再复制粘贴)。

总之,就感觉这道题目很神,学习了。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=1e6+5;

int n;
int d[maxn];
bool inq[maxn];
int prime[]={2,3,5,7,11,13};

void spfa()
{
memset(d,0x3f,sizeof(d));
memset(inq,0,sizeof(inq));
queue<int> Q;
Q.push(1);
d[1]=0;
inq[1]=1;
while(!Q.empty())
{
int u=Q.front(); Q.pop(); inq[u]=0;
for(int i=0;i<6 && prime[i]*u<n+5;i++)
{
int v=prime[i]*u;
if(d[v]>d[u]+prime[i])
{
d[v]=d[u]+prime[i];
if(!inq[v])  {inq[v]=1;Q.push(v);}
}
}
int v=u-1;
if(d[v]>d[u]+1)
{
d[v]=d[u]+1;
if(!inq[v])  {inq[v]=1;Q.push(v);}
}
}
printf("%d\n",d
);
}

int main()
{
//freopen("in.txt","r",stdin);
scanf("%d",&n);
spfa();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: