#include # define endl '\n' # define clr(x,a) memset(x,a,sizeof(x)) # define vi vector # define all(a) a.begin(), a.end() # define deb(x) cout<<#x<<"=="< smer[4]={{0, 1}, {0, -1}, {1, 0}, {-1, 0} }, sm[8]={{0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1} }, stek[3][7205]; int n, p, d, priz[mxN][mxN], res[10][mxN][mxN], tren_stranka, tren_okrug, skalirano_d=-1, brojac_stranke[12], tip, brojac_opstina[15]; int br_grupa, dh[5]={60, 60, 30, 25, 12}, dw[5]={120, 60, 50, 30, 30}; int okruzi_stranke[505][10], finres[mxN][mxN], finres2[mxN][mxN], posecen[mxN][mxN], globposecen, brstek[3], ps[10][mxN][mxN], okz[2][10]; bool na_ivici[305][305]; void unos(){ freopen("gerrymandering.in", "r", stdin); sc("%d%d%d", &n, &d, &p); if(n!=300) exit(14); for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++){ sc("%d", &priz[i][j]); brojac_opstina[priz[i][j]]++; } } if(d==25) skalirano_d=0; else if(d==50) skalirano_d=1; else if(d==120) skalirano_d=2; else if(d==240) skalirano_d=3; else if(d==500) skalirano_d=4; if(brojac_opstina[1]>=brojac_opstina[2]+18000) tip=1; else if(brojac_opstina[1]>=36000 && brojac_opstina[2]>=36000) tip=2; else tip=3; } void ispis(){ freopen("gerrymandering.out", "w", stdout); for(int i=1; i<=p; i++){ for(int j=1; j<=n; j++){ for(int z=1; z<=n; z++) pr("%d ", res[i][j][z]); cout<<"\n"; } cout<<"\n"; } } struct Grupa{ int polozaj, r, c, h, w; int pobednicke_stranke[max_polozaj][9]; }grupe[100]; //treba proveriti, za sad samo d==50 (50) int ko_pobedjuje(int r, int c, int h, int w){ for(int i=1; i<=p; i++) brojac_stranke[i]=0; for(int i=0; imaximum){ ret=i; maximum=brojac_stranke[i]; } else if(brojac_stranke[i]==maximum) ret=-1; } return ret; } void postavi(int r, int c, int h, int w){ tren_okrug++; for(int i=0; i=9){ if(mat[i][j+1].val==0) //stavljam nadesno mat[i][j+1].val=tren_okrug; else //stavljam nadole mat[i+1][j].val=tren_okrug; } else{ if(mat[i][j+1].val!=0) //ima nesto desno, ovaj mora dole mat[i+1][j].val=tren_okrug; else if(mat[i+1][j].val!=0) //ima nesto dole, ovaj mora desno mat[i][j+1].val=tren_okrug; else if(mat[i][j].p1==tren_stranka) //dole i desno su prazni, desno je njegova stranka mat[i][j+1].val=tren_okrug; else if(mat[i][j].p2==tren_stranka) //dole i desno su prazni, dole je njegova stranka mat[i+1][j].val=tren_okrug; else mat[i][j+1].val=tren_okrug; //oba su prazna, nema njegove stranke, ide nadesno } } } } popuni_res(); } } int calc_score(){ //izracuna za tren_stranku kolko pobeda je osvojila clr(okruzi_stranke, 0); for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++) okruzi_stranke[res[tren_stranka][i][j]][priz[i][j]]++; } int maxi, pobede=0, ret; for(int i=1; i<=d; i++){ ret=-1; maxi=0; for(int j=1; j<=p; j++){ if(okruzi_stranke[i][j]>maxi){ maxi=okruzi_stranke[i][j]; ret=j; } else if(okruzi_stranke[i][j]==maxi) ret=-1; } if(ret==tren_stranka) pobede++; } return pobede; } void make_ps(){ //pitanje dal bi radilo... zajebo sam se for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++){ for(int z=1; z<=p; z++){ ps[z][i][j]=ps[z][i][j-1]+ps[z][i-1][j]-ps[z][i][j]+(priz[i][j]==z); } } } } int calc_score_deo(int r, int c, int dh, int dw){ clr(okz, 0); //0 je posecen, 1 je sveostalo for(int i=0; imaxi){ maxi=okz[0][i]; p1=i; } else if(okz[0][i]==maxi) p1=-1; } maxi=0; for(int i=1; i<=p; i++){ if(okz[1][i]>maxi){ maxi=okz[1][i]; p2=i; } else if(okz[1][i]==maxi) p2=-1; } return (p1==tren_stranka)+(p2==tren_stranka); } void sacuvaj(){ for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) finres[i][j]=res[tren_stranka][i][j]; } void ucitaj(){ for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) res[tren_stranka][i][j]=finres[i][j]; } void sacuvaj_deo(int r, int c, int dh, int dw){ //nije isto kao "sacuvaj"!, ali koristi finres, deli ga na 0 i na 1 for(int i=0; i=2) int nadji_id(int nr1, int nc1){ if(uslov){ if(priz[nr1][nc1]==tren_stranka) return 0; else if(priz[nr1][nc1]<=2) return 1; else return 2; } else{ if(priz[nr1][nc1]==tren_stranka) return 0; else return 1; } } void priprema(int tr, int tc){ //priprema iz pocetnog polja, ubacuje njegove komse int nr1, nc1, id; globposecen++; brstek[0]=brstek[1]=brstek[2]=0; br2=br1=0; if(priz[tr][tc]==tren_stranka) br2++; else br1++; int druga_stranka=1; if(tren_stranka==1) druga_stranka=2; posecen[tr][tc]=globposecen; for(int i=0; i<=3; i++){ nr1=tr+smer[i].st; nc1=tc+smer[i].nd; if(na_ivici[nr1][nc1]) continue; id=nadji_id(nr1, nc1); brstek[id]++; stek[id][brstek[id]].st=nr1; stek[id][brstek[id]].nd=nc1; } } void algoritam2(int l){ //za tip == 2 int nr, nc, id, druga_stranka=1; if(tren_stranka==1) druga_stranka=2; while(l){ //algoritam if(br2-br1>=2){ if(brstek[1]) id=1; else if(brstek[2]) id=2; else id=0; } else if(br1>=(br2-1)){ if(brstek[0]) id=0; else if(brstek[2]) id=2; else id=1; } else{ if(brstek[2]) id=2; else if(brstek[0]) id=0; else id=1; } nr=stek[id][brstek[id]].st; nc=stek[id][brstek[id]].nd; brstek[id]--; if(posecen[nr][nc]==globposecen) continue; //vec sam je posetio if(moze(nr, nc)){ //ubacujem je u gang, izbacujem nju iz steka, a u stek ubacujem njene komsinice l--; if(priz[nr][nc]==tren_stranka) br2++; else if(priz[nr][nc]==druga_stranka) br1++; posecen[nr][nc]=globposecen; for(int i=0; i<=3; i++){ if(posecen[nr+smer[i].st][nc+smer[i].nd]!=globposecen && !na_ivici[nr+smer[i].st][nc+smer[i].nd]){ //ako je nisam vec posetio, i ako nije na ivici if(priz[nr+smer[i].st][nc+smer[i].nd]==tren_stranka) id=0; else if(priz[nr+smer[i].st][nc+smer[i].nd]==druga_stranka) id=1; else id=2; brstek[id]++; stek[id][brstek[id]].st=nr+smer[i].st; stek[id][brstek[id]].nd=nc+smer[i].nd; } } } } if(l) exit(99); } void algoritam(int l){ int nr, nc, id; while(l){ //algoritam if(brstek[1]) id=1; //ako postoji u steku1, uzimam nju, jednu maalu else if(brstek[0]) id=0; //mora se tren_stranka, jbg, sta je tu je else exit(140); nr=stek[id][brstek[id]].st; nc=stek[id][brstek[id]].nd; brstek[id]--; if(posecen[nr][nc]==globposecen) continue; //vec sam je posetio if(moze(nr, nc)){ //ubacujem je u gang, izbacujem nju iz steka, a u stek ubacujem njene komsinice l--; posecen[nr][nc]=globposecen; for(int i=0; i<=3; i++){ if(posecen[nr+smer[i].st][nc+smer[i].nd]!=globposecen && !na_ivici[nr+smer[i].st][nc+smer[i].nd]){ //ako je nisam vec posetio, i ako nije na ivici if(priz[nr+smer[i].st][nc+smer[i].nd]==tren_stranka){ brstek[0]++; stek[0][brstek[0]].st=nr+smer[i].st; stek[0][brstek[0]].nd=nc+smer[i].nd; } else{ brstek[1]++; stek[1][brstek[1]].st=nr+smer[i].st; stek[1][brstek[1]].nd=nc+smer[i].nd; } } } } } if(l) exit(99); } void solve_za_grid(int r, int c, int dh, int dw){ for(int i=0; imax_score) sacuvaj_deo(r, c, dh, dw); max_score=max(max_score, tren_score); priprema(r+1, c+dw-2); if(uslov) algoritam2(l); else algoritam(l); tren_score=calc_score_deo(r, c, dh, dw); if(tren_score>max_score) sacuvaj_deo(r, c, dh, dw); max_score=max(max_score, tren_score); priprema(r+dh-2, c+1); if(uslov) algoritam2(l); else algoritam(l); tren_score=calc_score_deo(r, c, dh, dw); if(tren_score>max_score) sacuvaj_deo(r, c, dh, dw); max_score=max(max_score, tren_score); priprema(r+dh-2, c+dw-2); if(uslov) algoritam2(l); else algoritam(l); tren_score=calc_score_deo(r, c, dh, dw); if(tren_score>max_score) sacuvaj_deo(r, c, dh, dw); max_score=max(max_score, tren_score); for(int i=1; i<=15; i++){ priprema(r+rand()%(dh-2)+1, c+rand()%(dw-2)+1); if(uslov) algoritam2(l); else algoritam(l); tren_score=calc_score_deo(r, c, dh, dw); if(tren_score>max_score) sacuvaj_deo(r, c, dh, dw); max_score=max(max_score, tren_score); } ucitaj_deo(r, c, dh, dw); } void dva_okruga_skupa(){ //za neke 5ica, za neke njesra. int dh1=dh[skalirano_d], dw1=dw[skalirano_d], priv, drug; //60 sa 120 for(tren_stranka=1; tren_stranka<=p; tren_stranka++){ tren_okrug=0; clr(na_ivici, 0); for(int i=1; i<=n; i+=dh1) for(int j=1; j+dw1-1<=n; j+=dw1) solve_za_grid(i, j, dh1, dw1); if(dw1==dh1) continue; priv=calc_score(); sacuvaj(); tren_okrug=0; clr(na_ivici, 0); for(int i=1; i+dw1-1<=n; i+=dw1) for(int j=1; j<=n; j+=dh1) solve_za_grid(i, j, dw1, dh1); drug=calc_score(); if(priv>drug) ucitaj(); } } void d25_posebno(){ int dh1=60, dw1=120, priv, finalscore; //60 sa 120 // cout<<"radim d25 posebno\n"; for(tren_stranka=1; tren_stranka<=p; tren_stranka++){ tren_okrug=finalscore=0; clr(na_ivici, 0); for(int i=1; i<=n; i+=dh1) for(int j=1; j+dw1-1<=n; j+=dw1) solve_za_grid(i, j, dh1, dw1); //__________ kad je desno solve_za_grid(1, 241, 120, 60); solve_za_grid(121, 241, 120, 60); postavi(241, 241, 60, 60); priv=calc_score(); if(priv>finalscore){ //kocka dole finalscore=priv; sacuvaj(); } // ucitaj(); // continue; // cout<<"prvi krug prosao\n";/* clr(na_ivici, 0); tren_okrug-=5; solve_za_grid(1+60, 241, 120, 60); solve_za_grid(121+60, 241, 120, 60); postavi(1, 241, 60, 60); priv=calc_score(); if(priv>finalscore){ //kocka gore finalscore=priv; sacuvaj(); } // cout<<"drugi krug prosao\n"; //___________ kad je levo tren_okrug=0; clr(na_ivici, 0); for(int i=1; i<=n; i+=dh1) for(int j=61; j+dw1-1<=n; j+=dw1) solve_za_grid(i, j, dh1, dw1); solve_za_grid(1, 1, 120, 60); solve_za_grid(121, 1, 120, 60); postavi(241, 1, 60, 60); priv=calc_score(); if(priv>finalscore){ //kocka dole finalscore=priv; sacuvaj(); } // cout<<"treci krug prosao\n"; clr(na_ivici, 0); tren_okrug-=5; solve_za_grid(1+60, 1, 120, 60); solve_za_grid(121+60, 1, 120, 60); postavi(1, 1, 60, 60); priv=calc_score(); if(priv>finalscore){ //kocka gore finalscore=priv; sacuvaj(); } // cout<<"cetvri krug prosao\n"; //_______________________________________________ dh=60 dw=120 gotov, ide sada 120 sa 60 swap(dh1, dw1); tren_okrug=0; clr(na_ivici, 0); for(int i=1; i+dh1-1<=n; i+=dh1) for(int j=1; j<=n; j+=dw1) solve_za_grid(i, j, dh1, dw1); //__________ kad je dole solve_za_grid(241, 1, 60, 120); solve_za_grid(241, 121, 60, 120); postavi(241, 241, 60, 60); priv=calc_score(); if(priv>finalscore){ //kocka desno finalscore=priv; sacuvaj(); } // cout<<"peti krug prosao\n"; clr(na_ivici, 0); tren_okrug-=5; solve_za_grid(241, 1+60, 60, 120); solve_za_grid(241, 121+60, 60, 120); postavi(241, 1, 60, 60); priv=calc_score(); if(priv>finalscore){ //kocka levo finalscore=priv; sacuvaj(); } // cout<<"sesti krug prosao\n"; //___________ kad je gore tren_okrug=0; clr(na_ivici, 0); for(int i=61; i+dh1-1<=n; i+=dh1) for(int j=1; j<=n; j+=dw1) solve_za_grid(i, j, dh1, dw1); solve_za_grid(1, 1, 60, 120); solve_za_grid(1, 121, 60, 120); postavi(1, 241, 60, 60); priv=calc_score(); if(priv>finalscore){ //kocka desno finalscore=priv; sacuvaj(); } // cout<<"sedmi krug prosao\n"; clr(na_ivici, 0); tren_okrug-=5; solve_za_grid(1, 1+60, 60, 120); solve_za_grid(1, 121+60, 60, 120); postavi(1, 1, 60, 60); priv=calc_score(); if(priv>finalscore){ //kocka levo finalscore=priv; sacuvaj(); } swap(dh1, dw1); ucitaj(); } } int brojilica[505][10]; void proverica(){ tren_stranka=1; for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++){ brojilica[res[tren_stranka][i][j]][priz[i][j]]++; } } for(int i=1; i<=d; i++){ cout<<"Za okrug: "<