17.11.08
- 上午 模拟考试
- Prob.1(WA30)
模拟,有点小烦。然后double转整型时没有long long,挂了3个点。
- Prob.2(WA70)
简化题目
给出了一个图(n点数<=2500)的两点间的最短距离的邻接矩阵。
问是否存在一颗 n个点的树的邻接矩阵和输入的相同。 (没有负权)
可以发现,如果存在的话,当前邻接表中最小的边一定是树中的一条边。
所以就 最小生成树prim算法,不用优先队列 n^2
然后就是求出当前树的两点间距离的邻接矩阵。比对就好了。
跑n次dfs就出来了 n^2
(智障的我:怎么求树上所有点之间的距离啊,Floyd n^3 要炸啊。简直莫法做,看来只能得30分了)
(、、、、Floyd?!蛤,我在干嘛、、)
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define MAXN 2505
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
ll to,val,next;
}e[MAXN*2];
ll ans[MAXN][2];
ll head[MAXN],fa[MAXN],mp[MAXN][MAXN],dis[MAXN][MAXN];
ll n,ent;
char gc(){
static char s[100005];
static int bit=100000,p,len;
if(p>=len) len=fread(s,1,bit,stdin),s[len]=EOF,p=0;
return s[p++];
}
void read(ll &x){
static int f;static char ch;
x=0; f=1; ch=gc();
while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=gc();}
while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=gc();}
x=x*f;
}
void add(ll u,ll v,ll w){
e[ent]=(edge){v,w,head[u]};
head[u]=ent++;
}
void Prim(){
static ll d[MAXN],from[MAXN];
static bool vis[MAXN];
memset(vis,0,sizeof(vis));
memset(d,0x3f,sizeof(d));
memset(head,0,sizeof(head));
vis[1]=1; ent=2;
for(ll i=2;i<=n;i++) if(d[i]>mp[1][i]) d[i]=mp[1][i],from[i]=1;
for(ll k=1,w,v;k<n;k++){
w=INF;
for(ll i=1;i<=n;i++) if(!vis[i]&&w>d[i]) w=d[i],v=i;
add(from[v],v,w); add(v,from[v],w); vis[v]=1;
ans[from[v]][0]+=w; ans[v][0]+=w;
ans[from[v]][1]+=1; ans[v][1]+=1;
for(ll i=1;i<=n;i++) if(!vis[i]&&d[i]>mp[v][i]) d[i]=mp[v][i],from[i]=v;
}
}
void dfs(ll u,ll dad,ll val,ll *DIS){
DIS[u]=val;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==dad) continue;
dfs(v,u,val+e[i].val,DIS);
}
}
void check(){
bool fg=1;
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
if(dis[i][j]!=mp[i][j]){fg=0;break;}
if(!fg) printf("No\n");
else{
double val=1.0*ans[1][0]/ans[1][1];ll ANS=1;
for(ll i=2;i<=n;i++) if(1.0*ans[i][0]/ans[i][1]>val)
val=1.0*ans[i][0]/ans[i][1],ANS=i;
printf("Yes\n%I64d\n",ANS);
}
}
void work(){
read(n);
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
read(mp[i][j]);
Prim();
for(ll i=1;i<=n;i++) dfs(i,0,0,dis[i]);
check();
}
void init(){
memset(ans,0,sizeof(ans));
memset(dis,0,sizeof(dis));
ent=0;
}
int main(){
freopen("treas.in","r",stdin);
freopen("treas.out","w",stdout);
ll T;
read(T);
while(T--){
init();
work();
}
return 0;
}
- Prob.3(WA10)
- 一个处理区间覆盖的题。他们都大佬地用O(n)做,我却在弱弱地用线段树维护、、、(就当复习了。)
-
注意!!!
1).这种题用到线段树的话,是以单位区间为底层节点的,方便。
2).离散化后,要在没有紧贴的点中间加入一些 "占位点")
(要不是数据善良,不然今天就又凉了)
- 补两个Tyvj上的题,之前忘了记录了。
- Tyvj P1480 星际大战
状压dp,
dp[S]表示选了"目标"集合为S的元素,这些元素依次被前几个导弹攻击的最小距离和。
然后刷表法,即枚举下一个导弹打哪个目标。
复杂度:2^n*n
代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const double eps=1e-6;
struct pos{
int x,y;
}mis[25],aim[25];
double d[25][25],dp[1<<20],hv[1<<20];
int n,all;
int idx(int i){
return 1<<i;
}
int sign(double x){
if(fabs(x)<=eps) return 0;
return x>0?1:-1;
}
void cmin(double &a,double b){
if(sign(a-b)>0) a=b;
}
double dis(pos a,pos b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main(){
scanf("%d",&n); all=(1<<n)-1;
for(int i=0;i<n;i++) scanf("%d%d",&mis[i].x,&mis[i].y);
for(int i=0;i<n;i++) scanf("%d%d",&aim[i].x,&aim[i].y);
for(int i=0;i<n;i++) for(int j=0;j<n;j++) d[i][j]=dis(mis[i],aim[j]);
for(int S=1;S<=all;S++) hv[S]=hv[S>>1]+(S&1),dp[S]=1e9;
for(int S=0,p;S<all;S++)
for(int i=0;i<n;i++){
if(S&idx(i)) continue;
p=hv[S]; cmin(dp[S|idx(i)],dp[S]+d[p][i]);
}
printf("%.3lf",dp[all]);
return 0;
}
- Tyvj P4112 删数问题
贪心,依次确定最高位。
显然在可取范围内,最高位越小越好,那么每次就查询可行区间的最小值的位置。
线段树维护(尝试了一下ZKW线段树,感觉很像镜像对称后的树状数组。)
(但是不会区间修改,感觉好麻烦啊,需要区间修改是我还是先直接打线段树吧)
代码:
#include<cstring>
#include<iostream>
#define MAXN 800
using namespace std;
char s[300],ans[300];
struct ZKW{
int mini[MAXN],pos[MAXN],M,N;
void update(int &fmini,int &fpos,int smini,int spos){
if(fmini<smini) return;
if(fmini==smini&&fpos<spos) return;
fmini=smini; fpos=spos;
}
void build(int n){
memset(mini,0x3f,sizeof(mini));
for(M=1;M<=n+1;M<<=1); N=n;
for(int i=1;i<=n;i++) mini[M+i]=s[i]-'0',pos[M+i]=i;
for(int i=M;i;i--)
update(mini[i],pos[i],mini[i<<1],pos[i<<1]),
update(mini[i],pos[i],mini[i<<1|1],pos[i<<1|1]);
}
int query(int l,int r){
int v=0x3f3f3f3f,p;
l=M+l-1; r=M+r+1;
for(;l^r^1;l>>=1,r>>=1){
if(~l&1) update(v,p,mini[l^1],pos[l^1]);
if(r&1) update(v,p,mini[r^1],pos[r^1]);
}
return p;
}
}T;
int main(){
int n,m,k,cnt=0,now=0;
scanf("%s",s+1); n=strlen(s+1);
T.build(n); int last=0;
scanf("%d",&m); k=n-m;
while(k){
int p=T.query(last+1,last+m+1);
ans[++cnt]=s[p];
m-=(p-last-1); k--;
last=p;
};
for(int i=1;i<=cnt;i++) now=now*10+ans[i]-'0';
printf("%d",now);
return 0;
}
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas

浙公网安备 33010602011771号