问题
https://vjudge.net/problem/UVA-10123
分析
一开始没看懂题目,不知道这种两个支点的怎么计算。
参考:https://blog.csdn.net/HelloWorld10086/article/details/38641299
优化的代码:https://www.cnblogs.com/staginner/archive/2011/12/21/2295362.html
所有的距离都乘以2,消除小数部分。
将拿下的部分倒过来看,看作是一个一个往上面放置的过程。
贪心:首先放中间的,然后再放两边的,两边的排序,按照力矩从小到大尝试往上放,左右两边轮流来。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn=20+5;
const double eps=1e-6;
struct Pack{
int pos,w;
double ll,lr,rr,rl;
Pack():pos(0),w(0),ll(0),lr(0),rr(0),rl(0) {}
};
bool cmp1(const Pack &lhs,const Pack &rhs){
return lhs.ll<rhs.ll;
}
bool cmp2(const Pack &lhs,const Pack &rhs){
return lhs.rr<rhs.rr;
}
vector<Pack> Left,Mid,Right,rec;
int n,s,kase=0;
double ll,lr,rr,rl,L,W;
bool DFS(int d,int ld,int rd,double lw,double rw){
if(d==n && lw<eps && rw<eps){
return true;
}
if(ld<Left.size() && lw+Left[ld].ll<eps){
rec.push_back(Left[ld]);
if(DFS(d+1,ld+1,rd,lw+Left[ld].ll,rw-Left[ld].lr)) return true;
rec.pop_back();
}
if(rd<Right.size() && rw+Right[rd].rr<eps){
rec.push_back(Right[rd]);
if(DFS(d+1,ld,rd+1,lw-Right[rd].rl,rw+Right[rd].rr)) return true;
rec.pop_back();
}
return false;
}
int main(void){
while(scanf("%lf%lf%d",&L,&W,&n)==3 && L){
Left.clear();
Mid.clear();
Right.clear();
rec.clear();
ll=lr=rr=rl=0;
L=2*L;
rl=lr=(L/2+3)*((3+L/2)/L*W)/2;
ll=rr=(L/2-3)*((L/2-3)/L*W)/2;
for(int i=0;i<n;++i){
Pack temp;
scanf("%d%d",&temp.pos,&temp.w);
temp.pos<<=1;
if(temp.pos<=3 && temp.pos>=-3){
rl+=(temp.pos+3.0)*temp.w;
lr+=(3.0-temp.pos)*temp.w;
Mid.push_back(temp);
rec.push_back(temp);
} else if(temp.pos<-3){
temp.ll=(-3-temp.pos)*temp.w;
temp.lr=(3-temp.pos)*temp.w;
Left.push_back(temp);
} else{
temp.rr=(temp.pos-3)*temp.w;
temp.rl=(temp.pos+3)*temp.w;
Right.push_back(temp);
}
}
sort(Left.begin(),Left.end(),cmp1);
sort(Right.begin(),Right.end(),cmp2);
printf("Case %d:\n",++kase);
if(!DFS(Mid.size(),0,0,ll-rl,rr-lr)) printf("Impossible\n");
else {
for(int i=rec.size()-1;i>=0;--i){
printf("%d %d\n",rec[i].pos>>1,rec[i].w);
}
}
}
return 0;
}
DP 状态压缩+记忆化搜索
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn=20+5;
const double eps=1e-6;
struct Pack{
int pos,w;
double ll,lr,rr,rl;
Pack():pos(0),w(0),ll(0),lr(0),rr(0),rl(0) {}
};
bool cmp1(const Pack &lhs,const Pack &rhs){
return lhs.ll<rhs.ll;
}
bool cmp2(const Pack &lhs,const Pack &rhs){
return lhs.rr<rhs.rr;
}
vector<Pack> pack,rec;
int n,kase=0,dp[1<<20],s;
double ll,lr,rr,rl,L,W;
int DP(int cur,double lw,double rw){
int &temp=dp[cur];
if(temp!=-1) return temp;
if(cur==s-1 && lw<eps && rw<eps){
return temp=1;
}
for(int i=0;i<n;++i){
if(cur&(1<<i)) continue;
double ld=pack[i].ll-pack[i].rl,rd=pack[i].rr-pack[i].lr;
if(lw+ld<eps && rw+rd<eps && DP(cur^(1<<i),lw+ld,rw+rd)==1){
rec.push_back(pack[i]);
return temp=1;
}
}
return temp=0;
}
int main(void){
while(scanf("%lf%lf%d",&L,&W,&n)==3 && L){
pack.clear();
rec.clear();
ll=lr=rr=rl=0;
L=2*L;
rl=lr=(L/2+3)*((3+L/2)/L*W)/2;
ll=rr=(L/2-3)*((L/2-3)/L*W)/2;
for(int i=0;i<n;++i){
Pack temp;
scanf("%d%d",&temp.pos,&temp.w);
temp.pos<<=1;
if(temp.pos<=3 && temp.pos>=-3){
temp.rl=(temp.pos+3.0)*temp.w;
temp.lr=(3.0-temp.pos)*temp.w;
} else if(temp.pos<-3){
temp.ll=(-3-temp.pos)*temp.w;
temp.lr=(3-temp.pos)*temp.w;
} else{
temp.rr=(temp.pos-3)*temp.w;
temp.rl=(temp.pos+3)*temp.w;
}
pack.push_back(temp);
}
printf("Case %d:\n",++kase);
s=1<<n;
//-1代表未访问,0代表该状态非法,1代表改状态合法
for(int i=0;i<s;++i) dp[i]=-1;
DP(0,ll-rl,rr-lr);
if(dp[(1<<n)-1]!=1) printf("Impossible\n");
else {
for(int i=0;i<rec.size();++i){
printf("%d %d\n",rec[i].pos>>1,rec[i].w);
}
}
}
return 0;
}