题解 P1220 【关路灯 】
并不会用dp做,,于是直接dfs,加个小小的剪枝,妥妥的0ms A了
#include<bits/stdc++.h>
using namespace std;
struct abc{
int p/*功率*/,place/*位置*/;
};
int ans=9999999,may,n,pl,all;abc s[55];bool z[55];//ans要取一个极大值,因为后面要取最小,不然的话就都是0
bool cmp(abc a,abc b)
{
if(a.place!=b.place) return a.place<b.place;//p代表功率,place代表这个灯的位置
}
void search(int now/*当前位置(在那盏灯下)*/)
{
bool is=false;int i;
if(may>ans) return;//小剪枝,如果当前的中间结果(or最终结果)超过ans,就return,这里的话,当时我的ans初始值还是0,所以>=就会进不去这个函数,所以就去掉了=,但后来我把ans的初始值定为了一个极大值,这样应该是可以加=的,并且加等于应该会更优
i=now;
while(z[i]&&i<n)i++;//右拐
if(!z[i])//如果灯是开的
{
z[i]=true;
may+=all*(s[i].place-s[now].place);
all-=s[i].p;
search(i);
all+=s[i].p;
may-=all*(s[i].place-s[now].place);
z[i]=false;
is=true;
i=now;//注意这里i要重置为now,因为不重置将可能把右拐的结果当做左拐来处理,然后就会出现负数,结果就偏小
}
while(z[i]&&i>1)i--;//左拐
if(!z[i])//如果找到的位置是开着灯的
{
z[i]=true;
may+=all*(s[now].place-s[i].place);
all-=s[i].p;
search(i);
all+=s[i].p;
may-=all*(s[now].place-s[i].place);
z[i]=false;
is=true;
i=now;
}
if(!is&&ans>may) ans=may;//一旦从当前位置可以左拐或右拐并找到开着的灯,is就会变成true,就代表灯没有关完,就不能改ans的值
}
int main()
{
int i;bool can=false;
scanf("%d%d",&n,&pl);
memset(z,0,55);
for(i=1;i<=n;i++)
{
scanf("%d%d",&s[i].place,&s[i].p);
all+=s[i].p;//all代表当前的总功率
if(i==pl&&!can) pl=s[i].place,all-=s[i].p,z[i]=true,can=true;//因为老张所处的那一盏灯可以视为瞬间关闭,所以减去它的电功率,另外pl改为那盏灯的位置,因为后面要sort一下,防止出错,另外因为改变了pl的值,所以要用一个bool型来记录有没有改过,不然的话可能会二次修改pl的值,因为某一个灯的位置很可能是另一盏灯的序号
}
sort(s+1,s+n+1,cmp);//根据灯的位置排序,是为了方便函数里面的计算
for(i=1;i<=n;i++)//根据之前pl里面存的初始位置来找初始的灯
if(pl==s[i].place)
{
pl=i;
break;//找到就break
}
search(pl);
printf("%d",ans);
return 0;
}