UVALIVE 6958 I 求某TSP路径长度恰为定值+meet in middle + 折半

/*
固定n-1为定点,先取一半点阶乘暴力,再取一半点阶乘暴力
*Rainto96
*Beijing University of Posts and Telecommunications School of Software Engineering
*http://blog.csdn.net/u011775691
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <climits>
#include<ctime>
using namespace std;
#define pb push_back
#define ALL(x) x.begin(),x.end()
#define VINT vector<ll>
#define PII pair<ll,ll>
#define MP(x,y) make_pair((x),(y))
#define ll long long
#define ull unsigned ll
#define MEM0(x)  memset(x,0,sizeof(x))
#define MEM(x,val) memset((x),val,sizeof(x))
#define scan(x) scanf("%lld",&(x))
#define scan2(x,y) scanf("%lld%lld",&(x),&(y))
#define scan3(x,y,z) scanf("%lld%lld%lld",&(x),&(y),&(z))
#define scan4(x,y,z,k) scanf("%lld%lld%lld%lld",&(x),&(y),&(z),&(k))
#define Max(a,b) a=max(a,b)
#define Min(a,b) a=min(a,b)
using namespace std;
struct Item{
        ll key,val,nxt;
};
struct UMP{
        Item item[5555];
        ll itnum;
        ll head[9973];
        ll MOD;
        UMP(){
                MOD=9973;
                clear();
        }
        void clear(){
                memset(head,-1,sizeof(head));
                itnum=0;
        }
        ll& operator[](ll x){
                ll idx=x%MOD;
                //cerr<<idx<<endl;
                for(ll i=head[idx];i!=-1;i=item[i].nxt){
                        if(item[i].key==x) return item[i].val;
                }

                item[itnum]=(Item){x,0,head[idx]};
                head[idx]=itnum;
                return item[itnum++].val;
        }
        bool count(ll x){
                if(x<0) return false;
                ll idx=x%MOD;
                //cerr<<idx<<endl;
                for(ll i=head[idx];i!=-1;i=item[i].nxt){
                        if(item[i].key==x) return true;
                }
                return false;
        }
}mp[16];
ll g[16][16];

int main(){
	#ifndef ONLINE_JUDGE
		//freopen("C:/OJ/in.txt","r",stdin);
		//freopen("C:/OJ/outmy.txt","w",stdout);
	#endif
	ll n,L;
	while(scan2(n,L)==2){
	        //cerr<<n<<" "<<L<<endl;
                for(ll i=0;i<n;i++)
                        for(ll j=0;j<n;j++)
                                scan(g[i][j]);
                vector<ll > v1,v2;
                ll s=(1<<(n-1))-1;
                bool suc=false;
                if(n==2){
                        if(g[0][1]+g[1][0]==L) puts("possible");
                        else puts("impossible");
                        continue;
                }
                for(ll i=(s-1)&s ; i; i=(i-1)&s ){
                        if(__builtin_popcount(i) == (n-1)/2 ){

                                for(ll i=0;i<n;i++) mp[i].clear();
                                v1.clear();
                                v2.clear();
                                for(ll j=0;j<n-1;j++){
                                        if(i&(1<<j)) v1.pb(j);
                                        else v2.pb(j);
                                }
                                v1.pb(n-1);

                                ll siz1=v1.size() , siz2=v2.size();
                                do{
                                        ll sum=0;
                                        for(ll j=0;j<siz1-1;j++) sum+=g[v1[j]][v1[j+1]];
                                        mp[v1[0]][sum]++;
                                }while(next_permutation(v1.begin() , v1.end()-1));

                                do{
                                        ll sum =0;
                                        for(ll j=0;j<siz2-1;j++) sum+=g[v2[j]][v2[j+1]];
                                        for(ll st=0;st<siz1-1 && !suc;st++){
                                                ll finder=L-sum-g[n-1][v2[0]]-g[v2[siz2-1]][v1[st]];
                                                //cerr<<"Find:"<<finder<<endl;

                                                if(mp[v1[st]].count(finder)){

                                                        suc=true;
                                                        break;
                                                }
                                        }
                                        if(suc) break;
                                }while(next_permutation(ALL(v2)));

                                //cerr<<clock()<<endl;
                                if(suc) break;
                        }
                }
                if(suc) puts("possible");
                else puts("impossible");
	}
        return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值