啊不小心点发布了,懒得删了就这样吧,虽然还没写完,也不打算写了大概。
d1t1
结论题 没什么好说的
d1t2
模拟 没什么好说的
d1t3
70分算法其实比较好想。
没有0边,就跑最短路,然后按dis从小到大转移。
场上最后十分钟才发现单向边,就没时间考虑0边,并且相当于傻逼一样排了个序,水了60;
肯定不能直接排序呀 n*k*log爆了啊,只把n个点按dis排序,然后先枚举一个k即可,肯定是从k小的转移到大的。
然后0边重新建图,拓扑排序,看环上有没有可行解,有就输出-1。否则把拓扑序作为第二关键字排序,转移即可。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
const int N=100005;
const int M=200005;
typedef long long LL;
using namespace std;
int T,n,m,k,p;
LL dp[N][51];
template<typename T> void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
if(ch==‘-‘) f=-1,ch=getchar();
for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘; x*=f;
}
int fir[N],nxt[M],to[M],val[M],ecnt;
int fif[N],nxf[M],tf[M],vaf[M],ecnf;
void add(int u,int v,int w) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
nxf[++ecnf]=fif[v]; fif[v]=ecnf; tf[ecnf]=u; vaf[ecnf]=w;
}
int fi[N],nx[M],tt[M],in[N],ec;
void Add(int u,int v) {
nx[++ec]=fi[u]; fi[u]=ec; tt[ec]=v; in[v]++;
}
queue<int>que;
int ds[N],dt[N],vis[N],tps[N];
void spfa(int s,int d[],int fir[],int nxt[],int to[],int val[]) {
d[s]=0;
vis[s]=1;
que.push(s);
while(!que.empty()) {
int x=que.front();
que.pop();
vis[x]=0;
for(int i=fir[x];i;i=nxt[i])
if(d[to[i]]>d[x]+val[i]) {
d[to[i]]=d[x]+val[i];
if(!vis[to[i]]) {
vis[to[i]]=1;
que.push(to[i]);
}
}
}
}
int tpsort() {
for(int i=1;i<=n;i++) if(!in[i]) que.push(i);
int idd=0;
while(!que.empty()) {
int x=que.front();
que.pop();
tps[x]=++idd;
for(int i=fi[x];i;i=nx[i]) {
if(!(--in[tt[i]]))
que.push(tt[i]);
}
}
for(int i=1;i<=n;i++)
if(in[i]&&ds[i]+dt[i]<=ds[n]+k)
return 1;
return 0;
}
struct node{
int x;
friend bool operator <(const node &A,const node &B) {
return ds[A.x]==ds[B.x]?tps[A.x]<tps[B.x]:ds[A.x]<ds[B.x];
}
}po[N*50];
void clear() {
ecnt=ec=ecnf=0;
memset(dt,127,sizeof(dt));
memset(ds,127,sizeof(ds));
memset(fi,0,sizeof(fir));
memset(fir,0,sizeof(fir));
memset(fif,0,sizeof(fif));
memset(in,0,sizeof(in));
memset(tps,0,sizeof(tps));
memset(dp,0,sizeof(dp));
}
void work() {
spfa(1,ds,fir,nxt,to,val);
spfa(n,dt,fif,nxf,tf,vaf);
if(tpsort()) printf("-1\n");
else {
int tot=0;
for(int i=1;i<=n;i++)
po[++tot].x=i;
dp[1][0]=1;
sort(po+1,po+tot+1);
for(int y=0;y<=k;y++) {
for(int o=1;o<=tot;o++) {
int x=po[o].x;
for(int i=fir[x];i;i=nxt[i])
if((LL)ds[x]+y+val[i]+dt[to[i]]<=ds[n]+k) {
(dp[to[i]][ds[x]+y+val[i]-ds[to[i]]]+=dp[x][y])%=p;
}
}
}
LL ans=0;
for(int i=0;i<=k;i++) (ans+=dp[n][i])%=p;
printf("%lld\n",ans);
}
}
void init() {
read(T);
while(T--) {
clear();
read(n);
read(m);
read(k);
read(p);
for(int i=1;i<=m;i++) {
int u,v,w;
read(u); read(v); read(w);
if(!w) Add(u,v);
add(u,v,w);
}
work();
}
}
#define DEBUG
int main() {
#ifdef DEBUG
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
#endif
init();
return 0;
}
d2t1
并查集
之前在长一考了一道有点像的二维的用并查集这样搞可以水80;
d2t2
一眼状压,然后不会。
推了半个小时prufer数列,并没有什么用。
自己对dp的理解还是太粗浅了。
一个可做的方法是,枚举层数,枚举状态,枚举补集,暴力转移。
你觉得十分不科学,然而事实是这样是可以得出正确答案的。
几个事。
1。不一定全部的状态或者转移都是最优的,只要最终可以达到最优解即可。
2。注意细节,如果层数枚举到12然后空间只开13你不就越界了嘛。。
3。省略一些不用的转移,比如dp==inf时直接略过,不然会死亡tle。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
#define inf 0x7fffffff
typedef long long LL;
using namespace std;
const int N=13;
int n,m,dis[N][N];
LL dp[N][1<<N];
template<typename T> void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
if(ch==‘-‘) f=-1,ch=getchar();
for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘; x*=f;
}
int q1[N],q2[N],t1,t2;
LL cal(int s,int t) {
t1=t2=0;
LL res=0;
for(int i=1;i<=n;i++) {
if(s&(1<<(i-1))) q1[++t1]=i;
if(t&(1<<(i-1))) q2[++t2]=i;
}
for(int i=1;i<=t2;i++) {
int tp=1e9;
for(int j=1;j<=t1;j++)
tp=min(tp,dis[q2[i]][q1[j]]);
res+=tp;
}
return res;
}
void work() {
int nn=(1<<n)-1;
LL ans=1e9;
for(int i=0;i<=n;i++)
for(int j=0;j<=nn;j++)
dp[i][j]=inf;
for(int i=1;i<=n;i++) dp[1][1<<(i-1)]=0;
for(int i=1;i<n;i++) {
for(int s=1;s<=nn;s++) if(dp[i][s]!=inf){
int bj=nn^s;
for(int vv=bj;vv;vv=(vv-1)&bj)
dp[i+1][s|vv]=min(dp[i+1][s|vv],dp[i][s]+i*cal(s,vv));
}
ans=min(ans,dp[i][nn]);
}
ans=min(ans,dp[n][nn]);
printf("%lld\n",ans);
}
void init() {
read(n);
read(m);
memset(dis,127/3,sizeof(dis));
for(int i=1;i<=m;i++) {
int u,v,w;
read(u); read(v); read(w);
dis[u][v]=min(dis[u][v],w);
dis[v][u]=dis[u][v];
}
}
int main() {
#ifdef DEBUG
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
init();
work();
return 0;
}
d2t3