ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【Topcoder 11107】TicketPrinters

2021-10-06 19:32:58  阅读:188  来源: 互联网

标签:typedef 个点 max mask 11107 long TicketPrinters Topcoder define


传送门

目前全网只找到了一篇简略的 dp 题解...

简明题意:

数轴上有 \(n\) 个点 \(p\),每个点上有一个数字 \(a\),每个点的坐标已知。有 \(n\) 个数字 \(b\),你需要把 \(n\) 个点和数字一一匹配。设第 \(i\) 个点和数字 \(j\) 匹配,则定义其点权为 \(w_i=|a_i-b_j|+1\)。

一开始你在点 \(k\),在点权确定后,你需要找到一种方法经过每一个点至少一次。设第 \(i\) 个点 \(t_i\) 秒被第一次经过,则答案为 \(\max_{w_i+t_i}\)。假设你的速度为 \(1\)。

你可以任意决定一开始的匹配,和确定匹配之后的行走方案。最小化答案。

Data range:\(n\le 16\)。

分析:

神仙题。

首先考虑已经经过的点形成一个区间,加上 \(n\) 很小,又出现了“匹配”这种字眼,容易想到区间状压 dp:设 \(f(l,r,mask,0/1)\) 是走完了 \([l,r]\),匹配完了 \(mask\) 里的数字,最后站在左端点/右端点上,所花的最小时间。

很快你发现这个转移是有问题的:因为这里存在两个“时间”:一个是你当前的 \(\sum t\),即用时,一个是目前已经出现的 \(\max\{w_i+t_i\}\),你的状态不能只记录其中的一个,又不可能记录两个。

为了控制变量,可以采用二分 \(\max\{w_i+t_i\}\) 的方式,正确性来讲应该是无问题的(我有空实现一发),但大概率会 TLE。

官方题解用了一个很神仙的方法:我们把这个东西倒过来做,状态里记录当前的 \(\max\{w_i+t_i\}\) 的值。每次向前推的时候,之前所有的 \(t_i\) 都会加上你要走的距离。所以直接加上去就好了。状态 \(f(l,r,mask,0/1)\) 表示 \([l,r]\) 还未处理,\(mask\) 集合里的数字未备选,当前站在左端点/右端点上,后面已经选完的部分的 \(\max\{w_i+t_i\}\) 的值。

时间复杂度 \(O(n2^n)\)。

这里有一个细节是我们不需要 \(r\) 这个变量,确定了 \(l\) 和 \(|mask|\) 就能知道 \(r\) 了。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define op(x) ((x&1)?x+1:x-1)
#define odd(x) (x&1)
#define even(x) (!odd(x))
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define lowbit(x) (x&-x)
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define next Cry_For_theMoon
#define il inline
#define pb(x) push_back(x)
#define is(x) insert(x)
#define sit set<int>::iterator
#define mapit map<int,int>::iterator
#define pi pair<int,int>
#define ppi pair<int,pi>
#define pp pair<pi,pi>
#define fr first
#define se second
#define vit vector<int>::iterator
#define mp(x,y) make_pair(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double db;
using namespace std;
const int MAXN=16,MAXM=(1<<16),INF=1e9;
int n,k,dis[MAXN],st[MAXN],ed[MAXN],ans=INF;
int g[MAXM],f[MAXN][MAXM][2];
int dp(int l,int mask,int flag){
	if(g[mask]==n)return 0;
	int& ret=f[l][mask][flag];if(ret!=INF)return ret;
	int r=l+g[mask]-1;int pos;if(flag==0)pos=l;else pos=r;
	if(l!=0){
		rep(i,0,n-1){
			if(mask&(1<<i))continue;
			ret=min(ret,max(abs(st[l-1]-ed[i])+1,dp(l-1,mask|(1<<i),0))+dis[pos]-dis[l-1]);
		}
	}
	if(r!=n-1){
		rep(i,0,n-1){
			if(mask&(1<<i))continue;
			ret=min(ret,max(abs(st[r+1]-ed[i])+1,dp(l,mask|(1<<i),1))+dis[r+1]-dis[pos]);
		}
		
	}
	return ret;
}
int solve(){
	rep(i,1,n-1)dis[i]+=dis[i-1];
	rep(i,1,(1<<n)-1){g[i]=1+g[i-lowbit(i)];}
	rep(i,0,n-1)rep(j,0,(1<<n)-1)rep(k,0,1)f[i][j][k]=INF;
	rep(i,0,n-1){
		ans=min(ans,max(abs(st[k]-ed[i])+1,dp(k,(1<<i),0)));	 
	}
	return ans;
}
class TicketPrinters{
public:
	int minTime(int currentPrinter,vector<int>printerDistance,vector<int>startingValues,vector<int>wantedValues){
		k=currentPrinter;n=printerDistance.size()+1;
		rep(i,1,n-1)dis[i]=printerDistance[i-1];
		rep(i,0,n-1){
			st[i]=startingValues[i];
			ed[i]=wantedValues[i];
		}
		return solve();
	} 
}test;

标签:typedef,个点,max,mask,11107,long,TicketPrinters,Topcoder,define
来源: https://www.cnblogs.com/Cry-For-theMoon/p/15372842.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有