codeforces 597
D题
在一个二维平面上面,有n个城市,现在每个城市都没有电。
你可以选择一些城市建发电站,代价是c[i];你也可以给每个城市拉电线,给城市(i,j)之间拉电线的代价是(abs(x[i]-x[j])+abs(y[i]-y[j]))*(k[i]+k[j])。
现在问你最少花费多少代价,能够使得全部城市都有电,输出方案。
题解
建立一个超级源点,每个城市与超级源点连边,权重为第i个城市建设发电站的代价
问题就转化为普通最小生成树问题
prim kruskal都可以
注意保留下路径
与0节点相连的都是自建发电站
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define sc(x) scanf("%I64d",&x);
#define si signed
#define fi first
#define se second
#define pb push_back
#define forn for(int i=0;i<n;i++)
int n;
#define P pair<int,int>
P A[2005];
int C[2005];
int K[2005];
int d[2005];
bool vis[2005];
int mp[2005][2005];
int pre[2005];
vector<int>v;
vector<P> vv;
void prim()
{
// vis[0]=1;
for(int i=1; i<=n; i++)
{
d[i]=1e18;
}
d[0]=0;
for(int i=0; i<=n; i++)
{
int x=-1;
for(int j=0; j<=n; j++)
if(!vis[j]&&(x==-1||d[j]<d[x]))x=j;
if(x==-1)break;
vis[x]=1;
for(int j=0; j<=n; j++)
{
if(!vis[j]){
if(d[j]>mp[x][j]){pre[j]=x;d[j]=mp[x][j];}
}
}
}
}
si main()
{
sc(n)
for(int i=1; i<=n; i++)
{
sc(A[i].fi)
sc(A[i].se)
}
for(int i=1; i<=n; i++)
{
sc(C[i])
mp[i][0]=mp[0][i]=C[i];
}
for(int i=1; i<=n; i++)sc(K[i]);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
mp[i][j]=(K[i]+K[j])*((labs(A[i].fi-A[j].fi))+(labs(A[i].se-A[j].se)));
}
}
prim();
int ans=0;
for(int i=0; i<=n; i++)
{
ans+=d[i];
}
cout<<ans<<'\n';
memset(vis,0,sizeof vis);vis[0]=1;
for(int i=1;i<=n;i++){
if(pre[i]==0){
v.push_back(i);
vis[i]=1;
}
}
cout<<v.size()<<endl;
for(int i=0;i<v.size();i++)cout<<v[i]<<' ';
cout<<endl;
for(int i=1;i<=n;i++){
if(!vis[i]){
vv.push_back(P(i,pre[i]));
vis[i]=1;
}
}
cout<<vv.size()<<endl;
for(int i=0;i<vv.size();i++)cout<<vv[i].fi<<' '<<vv[i].se<<endl;
}
C
简单dp,字符串中他会把源字符串的w翻译成uu,把m变成nn,现在给你一个字符串问他的源字符串有多少种
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define sc(x) scanf("%I64d",&x);
#define si signed
#define fi first
#define se second
#define pb push_back
#define forn for(int i=0;i<n;i++)
char s[100005];
const int mod= 1e9+7;
int dp[100005];
void init()
{
dp[0]=dp[1]=1;
for(int i=2;i<=100000;i++){
dp[i]=(dp[i-1]+dp[i-2])%mod;
}
}
si main()
{
init();
scanf("%s",s+1);
int n=strlen(s+1);
int ans=1;
for(int i=1;i<=n;){
if(s[i]=='w'||s[i]=='m'){
puts("0");
return 0;
}
if(s[i]=='u'){
int k=0;
while(i<=n){
if(s[i]=='u')k++,i++;
else break;
}
ans=(ans*dp[k])%mod;
}else if(s[i]=='n'){
int k=0;
while(i<=n){
if(s[i]=='n')k++,i++;
else break;
}
ans=(ans*dp[k])%mod;
}else i++;
}
cout<<ans<<'\n';
}
E
期望dp
现在有一个10*10的矩阵,玩家要从左下角走到左上角,会先往右边走,再往左边走,再往右边走(看NOTE里面的图),然后这个图里面有一些梯子,用梯子可以爬到上面去。
现在这个人在掷骰子,问你期望最少花费多少次,能够到达终点。
如果你到终点前,你的骰子超过了终点,那么将不会移动。
首先dp【i】表示走到第i步的最小期望,由于在终点附件那里如果步数超过,那只能原地走
dp【1】=1//6*(dp0+1)+5/6(dp1+1)
dp【2】=1/6*(dp0+1)+1/6*(dp1+1)+2/3*(dp2+1)
由于dp0=0;
故dp1至dp5可求出来是6;
接下来的每个点就是,先不考虑地图的梯子,先考虑转移
就是dp【i】+=sigma(j=1~6)【(1/6)*d[i-j]】
当有梯子时,直接考虑要不要用梯子就行,取min最小值
#include<bits/stdc++.h>
using namespace std;
const int maxn = 15;
double dp[maxn*maxn];
int idx[maxn][maxn];
int ladders[maxn*maxn];
int main(){
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
if(i%2){
idx[i][j]=(i*10+9-j);
}else{
idx[i][j]=(i*10+j);
}
}
}
// for(int i=0;i<10;i++){
// for(int j=0;j<10;j++){
// cout<<idx[i][j]<<' ';
// }
// puts("");
// }
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
int x;scanf("%d",&x);
ladders[idx[i][j]]=idx[i-x][j];
}
}
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
cout<<ladders[idx[i][j]]<<' ';
}
puts("");
}
dp[0]=0;
for(int i=1;i<6;i++)
dp[i]=6;
for(int i=6;i<100;i++){
double sum = 0;
for(int step=1;step<=6;step++){
sum = sum + min(dp[i-step],dp[ladders[i-step]]);
}
dp[i]=(sum/6)+1;
}
cout<< setprecision(10) << dp[99] << endl;
}
浙公网安备 33010602011771号