CSU 1116: Kingdoms 1117: 網格中的三角形 1119: Collecting Coins
阿新 • • 發佈:2019-02-04
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
#define INF 0x3f3f3f3f
int map[20][20],people[20],low[20];
int n,m,p;
int vis[20];
int prim(int t,int& sum)
{
memset(vis,0,sizeof(vis));
int pos,price,tot;
pos=1; price=0; tot=0;
for(int i=1;i<=n;i++)//尋找每種情況包含的點
{
vis[i]=t&1;
t=(t>>1);
if(vis[i]) tot++;//記錄有多少點
}
if(vis[1]==0) tot++;
for(int i=1;i<=n;i++)
{
if(vis[i]) low[i]=map [pos][i];
else low[i]=INF;
}
low[1]=0; vis[1]=2; tot--;//只需要將tot個點進行最小生成樹就行了
int MIN;
for(int k=1;k<=tot;k++)
{
MIN=INF; pos=1;
for(int i=1;i<=n;i++)
{
if(vis[i]==1&&MIN>low[i])
{
MIN=low[i]; pos=i;
}
}
if (pos==1) return INF;//如果存在點擴充套件不到,就果斷放棄這種情況
price+=low[pos]; sum+=people[pos]; vis[pos]=2;
for(int i=1;i<=n;i++)
{
if(vis[i]==1&&map[pos][i]<low[i])
low[i]=map[pos][i];
}
}
return price;
}
int main()
{
// freopen("s","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(map,0x3f,sizeof(map));
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++)
scanf("%d",&people[i]);//記錄每個城市的人數
for(int j=1;j<=m;j++)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
if(c<map[u][v])//處理重邊,保留花費最少的邊
{
map[u][v]=map[v][u]=c;
}
}
int price,sum,res=0;
// cout<<(1<<(n-1))<<endl;
for(int i=0;i<=(1<<(n));i++)//列舉點,對每個情況找一次最小生成樹
{
sum=people[1];
price=prim(i,sum);//返回總花費
if(price<=p) res=max(res,sum);//更新最大的人數
}
printf("%d\n",res);
}
return 0;
}
/**********************************************************************
Problem: 1116
User: 3901140225
Language: C++
Result: AC
Time:232 ms
Memory:2024 kb
**********************************************************************/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline ll max(ll a, ll b) {
return a > b ? a : b;
}
inline ll min(ll a, ll b) {
return a < b ? a : b;
}
ll N, M, A, B;
ll solve (ll k) {
if (k < 0)
k = 0;
if (N > M)
swap(N, M);
ll ans = 0;
for (ll n = 1; n <= N; n++) {
for (ll m = 1; m <= M; m++) {
ll cnt = 0;
if (n * m <= k)
cnt += 2 * (n + m - 2);
ll l, r;
for (ll x = 0; x <= n; x ++) {
r = (m * x + k) / n;
if (r > m)
r = m;
ll t = m * x - k;
if(t <= 0)
l = 0;
else
l = (t - 1) / n + 1;
if(l <= r)
cnt += 2 * (r - l + 1);
}
for (ll x = 1; x < n; x++) {
ll tmp = n * m - x;
if (tmp <= k)
cnt += 4 * (m - 1);
else {
tmp = tmp - k;
ll u = m-1 - min(tmp / x + (tmp % x != 0), m-1);
cnt += 4 * u;
}
}
//printf("%lld %lld %lld\n",n , m, cnt);
ans += cnt * (N - n + 1) * (M - m + 1);
}
}
return ans;
}
int main () {
int cas;
scanf("%d", &cas);
while (cas--) {
scanf("%lld%lld%lld%lld", &N, &M, &A, &B);
printf("%lld\n", solve(B*2) - solve(A*2-1));
}
return 0;
}
/**********************************************************************
Problem: 1117
User: 3901140225
Language: C++
Result: AC
Time:2364 ms
Memory:1120 kb
**********************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct node{
int x,y,flag;
};
node st[6];
node ccc[11];
int n,m;
int vis[30][30];
char map[30][30];
int zx,zy;
int cnt;
int res,ans,ans1;
int c,co;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int jude(int x,int y)
{
if(x<1||x>n||y<1||y>m) return 0;
return 1;
}
void dfs(int x,int y)
{
if(map[x][y]=='C') res++,map[x][y]='.';
vis[x][y]=1;
for(int i=0;i<4;i++)
{ int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(!jude(xx,yy)||vis[xx][yy]||map[xx][yy]=='O'||map[xx][yy]=='X') continue;
dfs(xx,yy);
}
}
void dfs4(int x,int y,node *df,int &co)//推完一個石頭能吃到的金幣個數
{
if(map[x][y]=='C') res++,map[x][y]='.',df[co].x=x,df[co++].y=y;//記錄金幣的位置,後面回溯。
vis[x][y]=1;
for(int i=0;i<4;i++)
{ int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(!jude(xx,yy)||vis[xx][yy]||map[xx][yy]=='O'||map[xx][yy]=='X') continue;
dfs4(xx,yy,df,co);
}
}
int dfs1(int x,int y,int zx,int zy)//判斷是否能到達推石頭的那個點。
{
vis[x][y]=1;
if(x==zx&&y==zy) return 1;
for(int i=0;i<4;i++)
{ int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(!jude(xx,yy)||vis[xx][yy]||map[xx][yy]=='X'||map[xx][yy]=='O') continue;
if(dfs1(xx,yy,zx,zy)) return 1;
}
return 0;
}
void solove(int num,int sum)//第幾個石頭,金幣和
{
if(num==cnt-1)//最後一個石頭推完
{
if(ans1<sum) ans1=sum;
return ;
}
if(ans+ans1==c) return ;
for(int i=1;i<cnt&&ans+ans1<c;i++)//暴力列舉石頭
{
if(!st[i].flag) continue ;
st[i].flag=0;
for(int j=0;j<4;j++)//列舉方向
{
int xx=st[i].x+dir[j][0];//根據你的位置得到的石頭的前後位置。
int yy=st[i].y+dir[j][1];
int x2=st[i].x-dir[j][0];
int y2=st[i].y-dir[j][1];
if(!jude(xx,yy)||map[xx][yy]=='C'||map[xx][yy]=='O'||map[xx][yy]=='X') continue;//當石頭後面不為空或者出界
if(!jude(x2,y2)||map[x2][y2]=='O'||map[x2][y2]=='X') continue;//當人站的那個位置還有石頭或者為障礙
memset(vis,0,sizeof(vis));
if(!dfs1(zx,zy,x2,y2)) continue;//當人不能到達推石頭的那個位置
map[st[i].x][st[i].y]='.';//能推就把石頭那個位置變成路
map[xx][yy]='X';//石頭後面的位置變成障礙
memset(vis,0,sizeof(vis));
int co=0;
node *df=(node*)malloc(sizeof(node)*10);//最多是個金幣,用來儲存這一輪完石頭所吃的金幣位置用於後面的回溯
res=0;
dfs4(zx,zy,df,co);//推完這次石頭然後去吃硬幣
solove(num+1,sum+res);//繼續往下面列舉石頭
for(int k=0;k<co;k++)//回溯地圖上的金幣
{
map[df[k].x][df[k].y]='C';
}
map[st[i].x][st[i].y]='O';//回溯石頭的位置
map[xx][yy]='.';
}
st[i].flag=1;
if(ans1<sum) ans1=sum;//取最大
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
cnt=1;
c=0;
for(int i=1;i<=n;i++)
{
scanf("%s",map[i]+1);
for(int j=1;j<=m;j++)
{
if(map[i][j]=='S')
{
zx=i;
zy=j;
map[i][j]='.';
}
if (map[i][j] == 'C') c++;
if(map[i][j]=='O')
{
st[cnt].x=i,st[cnt].y=j;
st[cnt++].flag=1;
}
}
}
res=0;
memset(vis,0,sizeof(vis));
dfs(zx,zy);//不推石頭直接能吃的金幣個數
ans=res;
ans1=0;
solove(0,0);
printf("%d\n",ans+ans1);
}
}
/**********************************************************************
Problem: 1119
User: 3901140225
Language: C++
Result: AC
Time:48 ms
Memory:1652 kb
**********************************************************************/