HDU--3920[Clear All of Them I] 状态压缩DP或模拟退火

25 篇文章 0 订阅
23 篇文章 0 订阅


PS、正解貌似是状态压缩DP,DP依旧不会、感觉和售货员问题差不多,于是试了下模拟退火居然还真水过去了= =!

 

后然用状态压缩DP也写了一次、、、、、


 

CODE(1):模拟退火

/*模拟退火*/
/*AC代码:890ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <ctime>
#include <cmath>
#define min(a,b) (a<b?a:b)
#define RunN 70
#define RanN 70
#define INF 1e8
using namespace std;
struct Node
{
    int link[25];
    double len;
};
struct Node node[RanN+5];
double X[40],Y[40];
double ox,oy;
double map[40][40];
double dis[40];
double ans;
bool vis[40];
int N,cas;

void adjust(Node &now,int rn)//rn为调整次数  
{  
    int i,u,v;  
    while(rn--)  
    {  
        u=rand()%(2*N)+1;
        v=rand()%(2*N)+1;
        if(u==v||now.link[u]==v) continue;
        int du=now.link[u];
        int dv=now.link[v];
        now.link[u]=v;
        now.link[v]=u;
        now.link[du]=dv;
        now.link[dv]=du;
    } 
    double len=0;
    memset(vis,false,sizeof(vis));
    for(i=1;i<=2*N;i++)
    {
        if(vis[i]) continue;
        v=now.link[i];
        len+=map[i][v];
        len+=min(dis[i],dis[v]);
        vis[i]=vis[v]=true;
    }
    now.len=len;
}  

void get_rnode()//产生RANN组初始数列  
{  
    int i,j;  
    for(i=0;i<RanN;i++)  
    {  
        for(j=1;j<=N;j++)
        {
            node[i].link[j]=j+N;
            node[i].link[j+N]=j;
        }
        adjust(node[i],N-1);//初始调整  
    }  
}  
void Run()
{
    int i,j;
    for(i=1;i<=2*N;i++)
    {
        map[i][i]=0;
        for(j=i+1;j<=2*N;j++)
        {
            map[i][j]=map[j][i]=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
        }
    }
    for(i=1;i<=2*N;i++)
        dis[i]=sqrt((X[i]-ox)*(X[i]-ox)+(Y[i]-oy)*(Y[i]-oy));
}
void Init()
{
    int i,j;
    scanf("%lf%lf",&ox,&oy);
    scanf("%d",&N);
    for(i=1;i<=2*N;i++)
        scanf("%lf%lf",&X[i],&Y[i]);
    Run();
    get_rnode();
}
void Print()
{
    int i;
    printf("--------------\n");
    for(i=0;i<RanN;i++)
        printf("%.2lf\n",node[i].len);
    printf("--------------\n");
}
void Solve()
{
    int i,j,u,v,t=N-1;
    Node temp;
    //Print();
    while(t--)
    {
        for(i=0;i<RanN;i++)
        {
            for(j=0;j<RunN;j++)
            {
                temp=node[i];
                adjust(temp,t);
                if(temp.len<node[i].len)
                    node[i]=temp;
            }
        }
    }
    double ans=INF;
    for(i=0;i<RanN;i++)
    {
        if(ans>node[i].len)
            ans=node[i].len;
    }
    printf("Case #%d: %.2lf\n",cas++,ans);
}
int main()
{
    int T;
    cas=1;
    srand(time(0));
    scanf("%d",&T);
    while(T--)
    {
        Init();
        Solve();
    }
    return 0;
}


 

 

CODE(2):状态压缩DP

/*状态压缩DP*/
/*AC代码:531ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <queue>
#include <cmath>
#define MAXN 2000000
#define INF 1e8
#define min(a,b) (a<b?a:b)
#define GOAL ((1<<(2*N))-1)
using namespace std;
int N,cas;
double X[30],Y[30];
double map[30][30];
double dis[30]; 
double ox,oy;
double dp[MAXN];
bool vis[MAXN];
int base[30];
void get_base()
{
    int i;
    base[0]=1;
    for(i=1;i<30;i++)
        base[i]=base[i-1]<<1;
}
void Run()
{
    int i,j;
    for(i=0;i<2*N;i++)
    {
        map[i][i]=0;
        for(j=i+1;j<2*N;j++)
        {
            map[i][j]=map[j][i]=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
        }
    }
    for(i=0;i<2*N;i++)
        dis[i]=sqrt((X[i]-ox)*(X[i]-ox)+(Y[i]-oy)*(Y[i]-oy));
    for(i=0;i<MAXN;i++)
        dp[i]=INF;
    dp[0]=0;
}
void Init()
{
    int i;
    scanf("%lf%lf",&ox,&oy);
    scanf("%d",&N);
    for(i=0;i<2*N;i++)
        scanf("%lf%lf",&X[i],&Y[i]);
    Run();
}
//类似SPFA
queue<int>Q; 
double BFS()
{
    int i,u,pos,state;
    double d;
	memset(vis,false,sizeof(vis));
    while(!Q.empty()) Q.pop();
    Q.push(0);
	vis[0]=true;
    while(!Q.empty())
    {
        
        u=Q.front();Q.pop();
		vis[u]=false;
		pos=2*N;
        for(i=0;i<2*N;i++)//先找到第一个为零的点,并固定下来
        {
            if((u&base[i])==0) 
            {pos=i;break;}
        }
        for(i=pos+1;i<2*N;i++)//然后O(N)扫描
        {
            if((u&base[i])==0) 
            {
                d=dp[u]+map[pos][i]+min(dis[i],dis[pos]);
                state=((u|base[pos])|base[i]);
                if(dp[state]>d)
                {
                    dp[state]=d;
					if(!vis[state])
					{
						vis[state]=true;
						Q.push(state);
					}
                }   
            }
            
        }
    }
    return dp[GOAL];
}
void Print()
{
    int i;
    printf("%d\n",GOAL);
    for(i=0;i<2*N;i++)
        printf("%.2lf ",dis[i]);
    printf("\n");
}
void Solve()
{
    //Print();
    double ans=BFS();
	printf("Case #%d: %.2lf\n",cas++,ans);
}
int main()
{
    int T;
    cas=1;
	get_base();
    scanf("%d",&T);
    while(T--)
    {
        Init();
        Solve();
    }
	return 0;
}


 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__简言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值