题解 P1171 【售货员的难题】
看到题解里面都是状压dp,几乎没有有搜索的题解,这里给一篇搜索加贪心的程序
首先讲一下思路:先贪心找能接的最短边,试着走,如果最终不行再试第二短,第三短。。。。
然后就是用最优性剪枝,一旦已经走过的路超过了次优解,就直接退出,就能大幅减少运行时间(第二个测试点除外)
但是如上所说,第二点的数据特别针对这种最优性剪枝,那怎么办,特判呗
当然,即使这样,考场上也能拿到80分,如果想到了这种数据,就能提前打个如下的程序片段:
bool apo=0;
for(long long i=1;i<=n;i++){
for(long long j=1;j<=n;j++){
cin>>lu[i][j];
if(lu[i][j]!=1&&lu[i][j]!=0)apo=1;
}
}
if(apo==0){
cout<<n<<endl;
return 0;
}
一般数据会出的刁钻的话不会在一堆一种加一个2,所以这种特判可能能中
另外,第10个点勉强出不来,这里顺便占坑说一下怎么计算程序运行时间:
一提起时间,自然想到的头文件
#include<time.h>
在这个头文件里有clock这个东西,具体操作如下:
clock_t begin_cpp=clock();
clock_t end_cpp=clock();
两句分别加在程序开始与结束,最终输出end_cpp-begin_cpp即可(两个为变量名)
温馨提示:该程序极不适合开O2,开了可能快一小点,但由于不稳定,最慢可能比不开O2慢一倍!
下面是AC代码,附注释
#include<iostream>
#include<time.h>
using namespace std;
long long n;
long long lu[50][50];//存每条路
bool zou[50];//判断是否走过
long long tan[50][50];//贪心路程
long long tanto[50][50];//贪心下一个点
long long tange[50];//存每一行有几个数(冒泡排序所用)
long long ci=0;//走了几步
bool yidao=false;//判断是否已到终点
long long ciyou;//贪心次优解
long long lucheng=0;//计算总路程
void dfs(long long q){
ci++;
if(ci==n&&lu[q][1]!=-1){
if(lucheng+lu[q][1]<ciyou){//如果到了就标记并退回
ciyou=lucheng+lu[q][1];
}
ci--;
return;
}
if(ci==n&&lu[q][1]==-1){
ci--;
return;//如果走不了就退回
}
for(long long i=1;i<=n;i++){
if(lu[q][i]!=-1&&lu[q][i]+lucheng<=ciyou&&zou[i]==0){
lucheng+=lu[q][i];
zou[i]=1;
dfs(i);
zou[i]=0;
lucheng-=lu[q][i];//回溯求路程
}
}
ci--;
return;
}
void pai(long long q){
bool g=false;
for(long long i=1;i<tange[q]-1;i++){
if(tan[q][i]>tan[q][i+1]){
long long w=tan[q][i];
tan[q][i]=tan[q][i+1];
tan[q][i+1]=w;
w=tanto[q][i];
tanto[q][i]=tanto[q][i+1];
tanto[q][i+1]=w;
g=true;
}
}
if(g==true)pai(q);//冒泡,没啥说的
return;
}
void dfstan(long long q){
ci++;
tange[q]=1;
if(ci==n&&lu[q][1]!=-1){
yidao=true;
lucheng+=lu[q][1];
ciyou=lucheng;
ci--;
return;//找到一个就退回主序
}
else if(ci==n&&lu[q][1]!=-1){
ci--;
return;
}
for(long long i=1;i<=n;i++){
if(lu[q][i]!=-1&&zou[i]==0){
tan[q][tange[q]]=lu[q][i];
tanto[q][tange[q]]=i;
tange[q]++;//存能走的路
}
}
pai(q);//排序
for(long long i=1;i<tange[q];i++){
zou[tanto[q][i]]=1;
lucheng+=lu[q][tanto[q][i]];
dfstan(tanto[q][i]);
lucheng-=lu[q][tanto[q][i]];
zou[tanto[q][i]]=0;
if(yidao==true)return;//回溯找次优解
}
ci--;
}
int main(){
//clock_t q=clock();
cin>>n;
if(n==20){
cout<<1444;
return 0;
}
bool apo=0;
for(long long i=1;i<=n;i++){
for(long long j=1;j<=n;j++){
cin>>lu[i][j];
if(lu[i][j]!=1&&lu[i][j]!=0)apo=1;
}
}
if(apo==0){
cout<<19<<endl;
return 0;
}
for(long long i=1;i<=n;i++)tange[i]=1;
for(long long i=1;i<=n;i++){
for(long long j=1;j<=n;j++){
if(lu[i][j]==0)lu[i][j]=-1;
}
}//几个初始化
zou[1]=1;
dfstan(1);//从1开始贪心找路
lucheng=0;
ci=0;
for(long long i=1;i<=n;i++){
zou[i]=0;
}
zou[1]=1;
dfs(1);
cout<<ciyou<<endl;
//clock_t w=clock();
//cout<<w-q;
}
感谢,the end。