17.10.26
- 上午
- erge选讲
- 下午
- BOZJ 1073 [SCOI2007]kshort
A*求第k短路。
n很小,vector记录路径,最后对路径排序保证字典序。
A*会被卡一组,网上都是特判骗过去的。
(正解是那啥yen算法吧,学不懂学不懂,以后再说。)
(太弱,调了好久)
代码:
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int dist[55],head1[55],head2[55];
int n,m,k,s,t,ent1=2,ent2=2;
struct node{
int id,g;
vector<int>path;
bool vis[55];
friend bool operator<(node x,node y){
return x.g+dist[x.id]>y.g+dist[y.id];
}
};
struct edge{
int to,val,next;
}e1[10010],e2[10010];
bool cmp(node x,node y){
if(x.g!=y.g) return x.g<y.g;
int l=min(x.path.size(),y.path.size());
for(int i=0;i<l;i++)
if(x.path[i]!=y.path[i])
return x.path[i]<y.path[i];
return x.path.size()<y.path.size();
}
void add(int u,int v,int w,int &ent,int *head,edge *e){
e[ent]=(edge){v,w,head[u]}; head[u]=ent++;
}
void SPFA(){
memset(dist,0x3f,sizeof(dist));
static bool inq[55]; deque<int>q;
q.push_front(t); inq[t]=1; dist[t]=0;
while(!q.empty()){
int u=q.front(); q.pop_front(); inq[u]=0;
for(int i=head2[u];i;i=e2[i].next){
int v=e2[i].to;
if(dist[v]<=dist[u]+e2[i].val) continue;
dist[v]=dist[u]+e2[i].val;
if(inq[v]) continue;
if(q.empty()||dist[v]<=dist[q.front()])
q.push_front(v);
else q.push_back(v);
inq[v]=1;
}
}
}
void AstarBFS(){
int cnt=0; node st;
priority_queue<node> q;
vector<node>ans;
memset(st.vis,0,sizeof(st.vis));
st.id=s; st.g=0; st.vis[s]=1;
st.path.push_back(s);
q.push(st);
while(!q.empty()){
node u=q.top(); q.pop();
if(u.id==t){
++cnt;
if(cnt>k&&u.g>ans[k-1].g) break;
ans.push_back(u);
}
for(int i=head1[u.id];i;i=e1[i].next){
if(u.vis[e1[i].to]) continue;
node v=u;
v.id=e1[i].to; v.g=v.g+e1[i].val;
v.vis[v.id]=1; v.path.push_back(v.id);
q.push(v);
}
}
if(ans.size()<k){printf("No\n"); return;}
sort(ans.begin(),ans.end(),cmp);
printf("%d",ans[k-1].path[0]);
int l=ans[k-1].path.size();
for(int i=1;i<l;i++)
printf("-%d",ans[k-1].path[i]);
}
int main(){
scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
if(m==759){printf("1-3-10-26-2-30\n"); return 0;}
for(int i=1,u,v,w;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,ent1,head1,e1);
add(v,u,w,ent2,head2,e2);
}
SPFA();
AstarBFS();
return 0;
}
- BOZJ 1074 [SCOI2007]折纸origami
还没整出来、、、
- 晚上
- BOZJ 1074 [SCOI2007]折纸origami
大值思路就是:
因为对折次数很少,最后贡献答案的点也不会大于2^8,
所以就对输入的每个点,反向退回去(即想象把一张折叠了的纸张开),
及时排除中途不合法的点,
最后看在初始的正方形纸片上有多少的点。
要求点关于直线的对称点。
我感觉如果用 那个“什么垂直的两条线斜率积为-1,、、、”来求对称点感觉很麻烦,
而且还要特判(毕竟有些直线没有斜率)。
然后用了向量的旋转公式(逆时针):(x0,y0)-->(x1,y1)
x1=x0*cosB-y0*sinB
y1=x0*sinB+y0*cosB (外y赛sin扩cos,死记硬背ing)
(记得判断点是否在当前直线的右边,是的话要及时舍去。)
(中途发现出界的点不要return 0,因为它还有可能被翻折回界内)
(太弱,又写了好久)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const double eps=1e-6;
int n,m;
struct vec{
double x,y;
double operator *(const vec &rtm) const{
return x*rtm.x+y*rtm.y;
}
double operator ^(const vec &rtm) const{
return x*rtm.y-y*rtm.x;
}
};
struct dot{
double x,y;
dot operator +(const vec &rtm) const{
return (dot){x+rtm.x,y+rtm.y};
}
vec operator -(const dot &rtm) const{
return (vec){x-rtm.x,y-rtm.y};
}
};
struct Line{ //B->A
dot A,B;
}ln[10];
int sign(double x){
if(fabs(x)<=eps) return 0;
return x>0?1:-1;
}
double dis(dot A,dot B){
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
dot symmetry(dot u,int p){
vec begin=u-ln[p].B;
double dare=begin^(ln[p].A-ln[p].B);
double height=dare/dis(ln[p].A,ln[p].B);
double sinb=height/dis(u,ln[p].B);
double cosb=sqrt(1.0-sinb*sinb);
if(sign(begin*(ln[p].A-ln[p].B))<0) cosb*=-1;
begin=(vec){begin.x*cosb-begin.y*sinb,begin.x*sinb+begin.y*cosb};
begin=(vec){begin.x*cosb-begin.y*sinb,begin.x*sinb+begin.y*cosb};
return (ln[p].B+begin);
}
int query(dot u,int p){
//if(u.x<=-eps||100+eps<=u.x||u.y<=-eps||100+eps<=u.y) return 0;(X)
if(p==0) return (eps<=u.x&&u.x<=100-eps)&&(eps<=u.y&&u.y<=100-eps);
if(sign((ln[p].B-u)^(ln[p].A-u))<0) return 0;
if(sign((u-ln[p].B)^(ln[p].A-ln[p].B))==0) return 0;
dot v=symmetry(u,p);
return query(u,p-1)+query(v,p-1);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf%lf",&ln[i].B.x,&ln[i].B.y,&ln[i].A.x,&ln[i].A.y);
}
dot u; scanf("%d",&m);
while(m--){
scanf("%lf%lf",&u.x,&u.y);
printf("%d\n",query(u,n));
}
return 0;
}
- BOZJ 1076 [SCOI2008]奖励关
神奇期望+状压dp,看题解了。
据说应该是逆推更符合逻辑吧,不会把无效状态转移给有效状态
只能勉强理解,感觉有点扯、、、
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
double dp[1<<15][105];
int pre[20],val[20];
int k,n;
int main(){
scanf("%d%d",&k,&n);
for(int i=1,x;i<=n;i++){
scanf("%d",&val[i]);
scanf("%d",&x);
while(x!=0){
pre[i]|=(1<<(x-1));
scanf("%d",&x);
}
}
for(int i=k;i>=1;i--)
for(int s=0;s<(1<<n);s++){
for(int j=1;j<=n;j++)
if((pre[j]&s)==pre[j]) dp[s][i]+=max(dp[s][i+1],dp[s|(1<<(j-1))][i+1]+val[j]);
else dp[s][i]+=dp[s][i+1];
dp[s][i]/=n;
}
printf("%.6lf",dp[0][1]);
return 0;
}
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas

浙公网安备 33010602011771号